Rust in Everything
基于 sqlx 0.9.0

编译期宏

这一部分是编译期检查主线:query! 在 cargo build 时被展开,在线时每个 crate 的编译要连一次数据库,离线时读 .sqlx 里的 JSON。代码都在 sqlx-macros-core 里:query/ 七个文件约 1.6k 行,database/ 不到 200 行,test_attr.rs 400 行;#[sqlx::test] 运行时的那一半在 sqlx-core/src/testing/ 和 sqlx-postgres/src/testing/。驱动那一侧的 describe 和可空性推断已经在 describe 与可空性推断 讲过,这里讲它的前后。

  1. query! 的流水线:12 个 query*! 都展开成同一个过程宏,差别在几个键值选项;expand_input 读 sqlx.toml 和 .env,决定连库还是读 .sqlx,再按 URL scheme 选驱动;编译期的连接按 URL 缓存在 rustc 进程里,每个 crate 一条,describe 结果本身不缓存。
  2. 生成的代码:用 cargo expand 看展开结果;参数检查是一段永不执行的 if false,让 rustc 在参数位置报类型错误;结果是匿名 Record,逐列 try_get_unchecked 再 into;列名后缀 !、?、: T 覆盖推断,: T 写错类型运行时不会报错。
  3. 离线模式与 sqlx.toml:cargo sqlx prepare 是带着环境变量跑一遍 cargo check,由宏写 .sqlx/query-<hash>.json;离线时怎么读回来;prepare --check 为什么能发现 schema 变化而离线构建不能;sqlx.toml 的 URL 变量名、类型覆盖和 preferred-crates,以及改了它为什么不触发重编译。
  4. #[sqlx::test]:每个测试一个临时库,库名由测试路径的哈希决定;迁移和 fixtures 在编译期嵌入;只有成功的测试才删库;URL 写死读 DATABASE_URL。
flowchart TB
  src["源码里的 query!"] --> pipe["流水线 选数据源"]
  pipe -->|在线| desc["describe 连库"]
  pipe -->|离线| json[".sqlx JSON"]
  desc --> gen["生成代码"]
  json --> gen
  desc -->|"SQLX_OFFLINE_DIR"| json
  gen --> run["运行时走查询主线"]

报错 set `DATABASE_URL` to use query macros online, or run `cargo sqlx prepare` to update the query cache 时怎么办,见常见坑 database-url-not-set;生成的类型里多了或少了 Option,见 unexpected-null。

💬 关联讨论

发起讨论
加载中...