mcpField
S
sqlx-code-review

sqlx-code-review

github.com/existential-birds测试与质量8593 次安装11 周前更新
代码仓库

关于 sqlx-code-review

sqlx-code-review 是用于审查 Rust 项目中 sqlx 数据访问代码的技能,面向代码审查者。它结合查询、连接池、事务、类型映射和迁移清单,并要求在定级前核实文件与行号证据。

主要功能

  1. 01检查 Cargo.toml 与 sqlx 配置
  2. 02审查查询模式和绑定参数
  3. 03检查连接池与事务处理
  4. 04核对 Rust 与 SQL 类型映射
  5. 05按证据门槛标注问题严重性

适用场景

  1. 01审查 Rust 项目的 sqlx 查询
  2. 02检查连接池配置和事务回滚路径
  3. 03评估数据库迁移的可逆性与安全性
  4. 04按文件行号整理审查发现

安装

复制下面的命令,在终端中运行。

$npx skills add https://github.com/existential-birds/beagle --skill sqlx-code-review

安装后在 Claude Code 中输入/sqlx-code-review确认已加载。

附带文件references/migrations.mdreferences/queries.md

详细介绍

sqlx 代码审查

审查工作流

  1. 检查 Cargo.toml — 记录 sqlx 功能(runtime-tokio、tls-rustls/tls-native-tls、postgres/mysql/sqlite、uuid、chrono、json、migrate)和 Rust 版次(2024 版更改了 RPIT 生命周期捕获,并不再需要 async-trait)
  2. 检查查询模式 — 编译时检查(query!、query_as!)与运行时检查(query、query_as)
  3. 检查连接池配置 — 连接数限制、超时、空闲设置
  4. 检查迁移 — 文件命名、可逆性、数据迁移安全性
  5. 检查类型映射 — Rust 类型与 SQL 列类型是否匹配

关卡(先收集证据,再判定严重程度)

按顺序完成;在通过对应声明的关卡之前,不要判定为 Critical / Major。

  1. 范围 — 确认正在审查的 crate(Cargo.toml 路径)以及你打开的 .rs 文件(或目录)。通过条件: 至少注明一个实际检查过的具体路径。
  2. sqlx / 编译声明 — 在声称存在与 query! / query_as!、离线模式、sqlx.toml、DATABASE_URL 或 Cargo 功能有关的问题之前,先打开相关的 Cargo.toml,并在适用时打开 sqlx.toml 或已记录的环境配置。通过条件: 问题注明了行号,或说明这些文件不存在 / 不在审查范围内。
  3. 问题定位 — 每个报告的问题都必须按 输出格式 包含 [FILE:LINE]。通过条件: Critical 或 Major 问题均有行号引用。
  4. 协议 — 在完成第 1–3 项关卡之后、给出最终严重程度标签之前,加载并完成 review-verification-protocol 技能。通过条件: 每个保留的问题均满足协议步骤。

输出格式

按如下格式报告问题:

[FILE:LINE] ISSUE_TITLE
Severity: Critical | Major | Minor | Informational
Description of the issue and why it matters.

快速参考

问题类型参考
查询宏、绑定参数、结果映射references/queries.md
迁移、连接池配置、事务模式references/migrations.md

审查清单

查询模式
  • 尽可能使用编译时检查的查询(query!、query_as!)
  • 配置 sqlx.toml 或 DATABASE_URL,以启用离线编译时检查
  • 查询中不使用字符串插值(存在 SQL 注入风险)——使用绑定参数($1、$2)
  • 对公共 API,query_as! 映射到具名结构体,而非匿名记录
  • 根据实际情况选择 .fetch_one()、.fetch_optional()、.fetch_all()
  • 对大型结果集使用 .fetch()(流式处理)
连接池
  • 通过 Arc 或框架状态共享 PgPool(不要为每个请求创建)
  • 根据部署环境配置连接池大小(生产环境不要保留默认值)
  • 设置连接获取超时
  • 配置空闲连接清理
  • 2024 版: 静态连接池单例初始化使用 std::sync::LazyLock(不要使用 once_cell::sync::Lazy 或 lazy_static!)
事务
  • 多语句操作使用 pool.begin()
  • 显式提交事务(不要依赖丢弃时隐式回滚)
  • 事务中的错误在传播之前触发回滚
  • 如有需要,嵌套事务使用保存点(tx.begin())
类型映射
  • sqlx::Type 派生与数据库列类型匹配
  • Rust、serde 和 SQL 中的枚举表示保持一致
  • 使用 Uuid、DateTime<Utc>、Decimal 类型(不要用字符串表示结构化数据)
  • 可空列使用 Option<T>
  • JSONB 列使用 serde_json::Value
  • 枚举变体或结构体字段不要命名为 gen——它是 2024 版的保留关键字(使用 r#gen 并添加 #[sqlx(rename = "gen")],或选择其他名称)
Edition 2024 兼容性
  • 返回 -> impl Stream 或 -> impl Future 的函数应考虑 RPIT 生命周期捕获变更(默认捕获所有作用域内的生命周期;使用 + use<'a> 进行精确控制)
  • 自定义 FromRow 或 Type trait 实现应在适用时使用 trait 中的原生 async fn(无需 #[async_trait],自 Rust 1.75 起稳定)
  • 仅在部分代码路径中使用的编译时查询字段,优先使用 #[expect(unused)] 而非 #[allow(unused)](可自行清理的 lint 抑制,自 Rust 1.81 起稳定)
  • 静态连接池初始化使用 std::sync::LazyLock(而非 once_cell 或 lazy_static!)
迁移
  • 迁移文件遵循命名约定(YYYYMMDDHHMMSS_description.sql)
  • 破坏性迁移(DROP、ALTER DROP COLUMN)可逆,或有数据备份计划
  • 不要在同一迁移中同时进行依赖数据的架构变更和数据变更
  • 在应用启动时调用 sqlx::migrate!()

严重性校准

严重
  • 在 SQL 查询中使用字符串插值(SQL 注入)
  • 多语句写入缺少事务(出错时会发生部分写入)
  • 每个请求都创建连接池(连接耗尽)
  • 缺少绑定参数转义
主要
  • 可使用编译时查询(query!())验证正确性的场景,却使用运行时查询(query())
  • 错误路径缺少事务回滚
  • Rust 与数据库之间的枚举类型不匹配
  • 对可能很大的表使用无界 .fetch_all()
  • 字段或变体命名为 gen,但未使用 r#gen 转义(edition 2024 编译失败)
次要
  • 在生产环境中使用未经调优的连接池默认值
  • 缺少 .fetch_optional()(使用 .fetch_one(),然后通过处理错误来应对“未找到”)
  • 只需要特定列时,却使用范围过宽的 SELECT *
  • 查询列缺少索引(仅当查询模式明显缓慢时标记)
  • Edition 2024:在 std::sync::LazyLock 可用时仍使用 once_cell::sync::Lazy 或 lazy_static!
  • 查询字段使用 #[allow(unused)] 而非 #[expect(unused)](优先采用可自行清理的 lint 抑制)
信息性
  • 建议使用 query_as! 进行类型安全的结果映射
  • 建议在 Rust 校验之外添加数据库级约束
  • 改进迁移组织方式

有效模式(不要标记)

  • 对动态查询使用运行时 query() —— 编译时检查不适用于动态 SQL
  • sqlx::FromRow derive —— 可作为 query_as! 的有效替代方案,用于可复用的行类型
  • 使用 TEXT 列存储枚举 —— 配合 sqlx::Type derive 有效,且比自定义 SQL 类型简单
  • .execute() 忽略行数 —— 对幂等操作(upsert、删除)可以接受
  • 与其他语言共享数据库 —— 例如,由 Elixir 管理迁移,Rust 负责读取。这是有效的架构。
  • 使用 r#gen 并配合 #[sqlx(rename = "gen")] —— 对数据库类型中的 gen 列,这是正确的 edition 2024 解决方案
  • 在查询辅助函数的返回类型上使用 + use<'a> —— 精确控制 RPIT 生命周期捕获(edition 2024)
  • 使用 std::sync::LazyLock 初始化静态连接池 —— 替代 once_cell/lazy_static(自 Rust 1.80 起稳定)
  • 在自定义 FromRow/Type trait 实现中使用原生 async fn —— 不再需要 async-trait crate(自 Rust 1.75 起稳定)

提交发现前

完成 Gates(严重性评定前的证据),然后加载并遵循 review-verification-protocol 技能,再报告任何问题。

评论

支持 Markdown