SuperAPI AI 工具集

update-sqlx

编程与开发

查看项目

更新于 10-16 06:10

技能介绍

用途

Windmill 在 CI 中使用 SQLX_OFFLINE=true,这要求所有 sqlx::query! / sqlx::query_as! 宏都能在 backend/.sqlx/ 中找到匹配的缓存查询数据。当在 Rust 源码中添加或编辑 SQL 查询后,必须更新该缓存,否则 CI 会报错:

error: `SQLX_OFFLINE=true` but there is no cached data for this query

本技能提供了一套安全更新 SQLx 离线查询缓存的操作流程。

主要能力

  • 在运行 prepare 前后备份与恢复缓存,避免编译失败导致缓存被清空(文中记录观察到 2350 → 142 条目的情况)。
  • 通过脚本 .agents/skills/update-sqlx/sqlx-cache.sh 提供 backup、newq、restore 等操作。
  • 提供保持 EE(企业版)缓存不被误删的安全流程,通过 git checkout origin/main -- .sqlx/ 恢复、运行 OSS feature 的 prepare、再补回缺失的 EE 缓存文件。
  • 提供缓存完整性验证步骤,比较 origin/main 与当前缓存文件列表,确保缺失文件数为 0。

使用方式

何时运行

在 Rust 源码中添加或编辑 SQL 查询后运行。

当变更只是删除查询时不要运行——缓存对 CI 而言已经是完整的,剩下的是孤立条目,仅是外观问题,不会破坏构建。应在离线状态下删除它们,而不是运行 prepare 整理。

运行前准备

备份缓存,因为 prepare 会在重新生成前删除 .sqlx/,任何编译失败都会使缓存被掏空:

.agents/skills/update-sqlx/sqlx-cache.sh backup

备份状态按 worktree 隔离,因此同时运行的兄弟 worktree 的 prepare 无法覆盖你的备份。

将 DATABASE_URL 指向当前 worktree 的数据库。prepare 会将每个 sqlx::query! 对着实时数据库编译。另一个 worktree 的数据库缺少你的迁移,因此每个新表查询都会失败并连带破坏缓存。症状是 relation "<your_new_table>" does not exist——这是 DATABASE_URL 错误,不是查询本身有问题。

测试中的查询需要 --all-targets

prepare 只缓存它编译到的代码中的查询,而仅 --workspace 不会编译测试目标。因此 tests/*.rs 中的 sqlx::query! 不会获得缓存条目,即使 lib 构建干净,CI 也会在测试目标上以常见的“no cached data”错误失败。

添加 --all-targets 可以缓存它们,但在 CE checkout 中会中途中止:backend/tests/otel.rs 导入了 windmill_common::otel_ee,它仅存在于私有 feature 之后,因此编译在 prepare 已经清空 .sqlx/ 之后死亡(观察到 2435 → 4 条目)。

遇到这种情况不要对抗它——这是预先存在的 EE 缺口,不是你的变更引起的。取走你需要的条目并恢复备份:

.agents/skills/update-sqlx/sqlx-cache.sh backup

cd backend
DATABASE_URL=<this worktree's db> \
  cargo sqlx prepare --workspace -- --workspace --features all_sqlx_features --all-targets
# 预期会失败;它仍然写入了死亡前获得的条目
cd ..

.agents/skills/update-sqlx/sqlx-cache.sh newq      # prints each added query
.agents/skills/update-sqlx/sqlx-cache.sh restore   # backup back, added entries grafted on

运行 restore 前先阅读 newq 打印的内容——它显示每个新增条目的 query 字段,每一条都应该是你的。集合很小(每个新测试查询一条);如果其中出现其他内容,说明运行走得比你想象的更远。

安全流程

始终从 origin/main 保留现有 EE 缓存:

cd backend

# 1. 从 main 恢复完整缓存(含 EE 缓存)
git checkout origin/main -- .sqlx/

# 2. 使用 OSS feature 运行 prepare(本地能编译的部分)
cargo sqlx prepare --workspace -- --workspace --features all_sqlx_features

# 3. 恢复在步骤 2 中被删除的 EE 缓存
git ls-tree origin/main backend/.sqlx/ \
  | awk '{print $4}' | sed 's|backend/\.sqlx/||' | sort > /tmp/main_files.txt

find backend/.sqlx -name "*.json" -printf '%P\n' | sort > /tmp/current_files.txt

comm -23 /tmp/main_files.txt /tmp/current_files.txt > /tmp/missing_files.txt

while read f; do
  git show "origin/main:backend/.sqlx/$f" > "backend/.sqlx/$f"
done < /tmp/missing_files.txt

# 4. 验证没有从 main 丢失任何内容
find backend/.sqlx -name "*.json" -printf '%P\n' | sort > /tmp/current_files.txt
comm -23 /tmp/main_files.txt /tmp/current_files.txt | wc -l
# 应输出:0

如果 EE 能在本地编译,可以使用完整脚本(更快):

cd backend
./update_sqlx.sh

但如果它以 EE 编译错误失败,则使用上述安全流程。

适用场景

  • 在 Windmill 仓库中新增或修改 SQL 查询后更新 SQLx 离线缓存。
  • 需要在 CI(SQLX_OFFLINE=true)下保持缓存完整。
  • 需要避免误删 EE 查询缓存的情况。

限制与禁止事项

  • 绝不要仅用 OSS feature 运行 cargo sqlx prepare --workspace 并提交结果——它会删除 EE 缓存。
  • 绝不要在本地 prepare 时设置 SQLX_OFFLINE=true——应使用实时数据库。
  • 绝不要在未备份 .sqlx 或未确认 DATABASE_URL 属于当前 worktree 的情况下运行 prepare。
  • 对于纯删除查询的变更绝不要运行 prepare。
  • 绝不要跳过验证步骤(上述步骤 4)。
  • 绝不要在 --all-targets 运行中止后保留其输出——那是一个近乎空的缓存。应恢复备份并仅嫁接已验证的条目。
  • 步骤 4 与 origin/main 比较是因为步骤 1 从它恢复;如果未运行步骤 1,应与 git merge-base HEAD origin/main 比较。

验证

提交后,与 origin/main 的 diff 应显示:几个新增缓存文件(对应你更改的查询)、几个删除的缓存文件(对应不再存在的旧查询)、EE 缓存集净删除为零。

git diff origin/main --stat backend/.sqlx/