《用 Rust + GPUI 做了一个开源数据库客户端:FluxDB》

用 Rust + GPUI 做了一个开源数据库客户端:FluxDB

最近在做一个开源桌面项目 FluxDB:用 Rust 和 GPUI,把 SQL 查询、表数据编辑、结构管理和 Redis 浏览放进同一个应用。

目前支持 MySQL、TiDB、PostgreSQL、SQLite 和 Redis,提供 macOS、Windows 和 Linux 安装包。

数据库客户端并不是新方向,DBeaver、DataGrip、Navicat 等工具已经很成熟。我想分享的也不是"又一个工具要替代谁",而是:选择 Rust + GPUI 这条原生桌面路线后,一个数据库客户端需要处理哪些问题。

项目地址:github.com/fluxdb-alt/...

先说现在能做什么

FluxDB 目前的基础功能包括:

  • 查询与编辑 SQL:语法高亮、代码折叠、表列补全、格式化和查询历史。
  • 浏览和修改数据:分页、筛选、单元格编辑、数据导出与 SQL 文件执行。
  • 管理表结构:查看列和 DDL,创建、修改表。
  • 查看 ER 关系:展示数据库外键,也可以手动记录本地逻辑关系。
  • 操作 Redis:浏览和编辑键值,使用工作台和命令终端。
  • 多连接工作区:通过侧边栏和标签页切换数据库对象,支持明暗主题。

这些功能不是在每种数据库上完全对等。例如 Redis 的操作对象是键值,而不是关系型数据库里的表;各数据库的实际支持范围可以看项目说明和操作手册。

下面聊几个实现上的取舍。

1. 选了原生 UI,不代表性能问题就自动解决了

FluxDB 的界面使用 GPUI,也就是 Zed 所使用的 UI 框架,不通过 Electron 或 WebView 绘制。

选择这条路线,意味着界面、状态和数据库相关逻辑都可以围绕 Rust 组织,也能复用 GPUI 生态里的表格、输入框和弹层等组件。

但"使用原生框架"不等于"应用天然流畅"。

对于数据库客户端,阻塞可能来自很多地方:

  • 展开数据库节点时,一次读了太多元数据。
  • 查询和数据提交占用了界面处理路径。
  • 切换标签页后,上一次请求的结果才返回。
  • 每次打开关系图,都重新读取同一份表结构。

所以,比框架标签更重要的是:界面需要什么数据、什么时候读取、结果回来后还应不应该使用。

目前我没有提供与其他客户端的统一性能基准,也不会仅凭 Rust + GPUI 就宣称启动更快、内存更低。这样的结论需要明确的环境、数据集和测量方法。

2. 点击"保存"之后,不能只剩一个数据库调用

以表格编辑为例,用户修改一个单元格,看起来只是输入了一个新值。真正提交时,还需要处理等待状态、失败反馈,以及数据库写入后如何刷新界面。

FluxDB 把这类工作分成几层,简化来看是:

text 复制代码
桌面界面:渲染、输入、交互
          |
       AppCommand
          |
应用层:状态与业务编排
          |
     Connector 接口
          |
具体数据库实现

结果再通过应用状态和事件回到界面。领域模型与 Connector 契约放在 Core,持久化由独立的 Storage 层负责。

这样做不只是为了把目录分得整齐。

例如数据提交,应用层把它分成准备、后台执行、结果回填几个阶段:

  1. 先进入提交状态,让界面及时显示正在保存,并阻止重复提交。
  2. 在后台完成数据库写入,以及需要的重新加载。
  3. 把结果交回界面:成功时同步原始数据与改动状态;失败时显示错误,保留尚未成功提交的改动。

另一个细节是,"写入失败"和"写入后的刷新失败"不能混成同一个错误。

后一种情况下,数据可能已经写入数据库。如果用户把它理解为"没有保存成功"而重复提交,就可能产生不必要的写入。因此,相关错误需要区分保存与刷新阶段,而不是统一弹一个"操作失败"。

类似地,数据库之间也不能简单套同一份逻辑。项目里的 PostgreSQL 数据提交会结合原始页面值构造保护条件;这不意味着所有数据库、所有查询结果都拥有相同的并发保护能力。

做数据库工具时,"能把新值写进去"只是开始,把失败语义解释清楚同样重要。

3. 元数据也需要按需加载

我们很容易注意到查询结果有多少行,却忽略表结构和关系信息也有规模问题。

打开一个库时,可能需要读取表名、注释、字段、主键、外键。把这些信息一次性全部读完,再交给 UI,并不总是合适的。

FluxDB 的 ER 画布采用分阶段加载:

  • 先读取表目录,让画布可以展示表节点。
  • 按视口需要读取字段。
  • 后台加载关系索引,再补充连线与关系布局。

字段和关系数据由应用层缓存,不让每个标签页各读一遍。同一份元数据的在途请求也会去重,数据库查询放在缓存锁之外。

缓存还涉及一个容易被忽略的问题:名称不是完整身份。

PostgreSQL 的不同 Schema 可以有同名表,标识符里也可能包含点号。如果直接把界面上的展示名称当作唯一键,或者用字符串切分反推 Schema,就很容易混淆对象。

因此,这里的缓存键不仅包含表名,还包含连接、连接修订、数据库和 Schema 等信息。连接配置发生变化后,旧修订下的结果不能继续当作当前数据使用。

这是一个比"加个缓存"更具体的约束:既要少读数据库,也不能为了复用而把旧结果用错地方。

4. "关系图上的一条线"不一定是数据库约束

关系图还有一个语义问题:数据库声明的外键,与用户在客户端记录的业务关系,不应该混在一起。

FluxDB 将两者区分:

  • 数据库外键来自数据库元数据。
  • 本地逻辑关系由用户手动建立并确认,保存在 FluxDB 中。

本地逻辑关系可以帮助梳理表之间的联系,但不会因为画了一条线,就执行 DDL、创建数据库外键,或者让数据库开始强制校验数据完整性。

关系是否经过确认、当前引用的表和字段是否仍然有效,也要单独记录。结构变化后,失效的关系不能继续作为有效连线展示。

这类功能的难点不只是连线怎么画,而是:界面表达的含义,不能超过底层事实。

5. 跨平台不只是编译出三个可执行文件

FluxDB 提供 macOS 的 ARM64/Intel DMG、Windows x64 安装器,以及 Linux x64 DEB。

但生成安装包只是其中一步,还要处理:

  • 图标、资源目录与桌面启动项。
  • 各平台原生构建依赖和动态库。
  • Windows 下外部子进程的控制台窗口。
  • macOS 签名、公证与首次启动拦截。
  • Linux 发行版依赖与图形环境差异。

项目通过 GitHub Actions 为不同平台构建和打包,并生成 SHA-256 校验文件。macOS 的打包脚本还需要处理应用资源和动态库。

这里也需要区分两个结论:有对应平台的安装包,不代表已经覆盖所有硬件与系统环境。

目前 macOS 安装包采用 ad-hoc 签名,尚未公证;Linux 提供的是 DEB,并没有同时覆盖 AppImage、Flatpak 等分发形式。遇到兼容性问题时,具体的系统版本和架构信息很有帮助。

关于 AI,以及项目现在的边界

项目开发中大量使用 AI,代码生成主要由 AI 完成,人工负责需求定义、变更审阅和验收。这不是所有实现都已经可靠的证明,尤其是数据库工具,还需要持续核实写入、安全和异常处理的边界。

同时,"用 AI 开发项目"和"产品里提供 AI 功能"是两件事。

本文的已发布基础能力以 v0.1.7 为参考。开发分支和演示视频中包含 AI 助手、分析报告等探索,但 v0.1.7 的 AI 入口尚未开放,不能据此认为下载该版本就能使用视频中的全部功能。

后续发布时,功能范围以对应 Release 说明为准。

这也是目前需要继续做好的事情:不仅完善功能,也让安装包、文档和演示保持一致。

下载与反馈

如果你正在尝试 Rust 原生桌面开发,或者想试试另一个开源数据库客户端,欢迎看看 FluxDB:

项目使用 GPL-3.0-or-later 许可证,当前界面主要为中文,仍处于早期阶段。建议先用测试库试用,操作重要数据前做好备份。

比起一句"好不好用",我更希望收到具体反馈:哪个系统上安装失败、哪种数据库连接有问题,或者哪个操作和你的预期不同。提交 Issue 时附上应用版本、系统与数据库版本,以及脱敏后的复现步骤,会更容易定位。

如果这些取舍也对你做桌面工具有所帮助,欢迎交流;如果 FluxDB 对你有用,也欢迎 Star 或参与贡献。

相关推荐
roman_日积跬步-终至千里1 小时前
【数据Agent论文·查询与语义|09】Spider 2.0:从生成SQL走向完成企业工作流
数据库·sql·数据分析
曦夜日长1 小时前
MySQL系统篇,数据库基础(二):数据库概念、SQL 分类与存储引擎
数据库·sql·mysql
泡海椒1 小时前
JQuick-SQL AST 解析:从 SQL 文本到强类型节点
数据库·sql
要开心吖ZSH1 小时前
SeaTunnel + Doris + MySQL-CDC 数据同步故障排查个人笔记
数据库·mysql·doris·seatunnel·mysql cdc
data analyse 4561 小时前
Session数怎么计算?明确会话切分、超时与跨页规则
java·服务器·数据库
骑着蜗牛撵大象3271 小时前
ToolJet + PostgreSQL:后台表格、查询和流程,一次搭成可远程访问的业务系统
数据库·低代码·docker·postgresql·内部工具·tooljet
先知后行。1 小时前
各种文件系统
linux·服务器·数据库
风若寒892 小时前
MySQL 主从同步,从库中断时间过长,需要主库全量进行覆盖一次
数据库·mysql·主从