编译期宏
这一部分是编译期检查主线: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 与可空性推断 讲过,这里讲它的前后。
- query! 的流水线:12 个
query*!都展开成同一个过程宏,差别在几个键值选项;expand_input读sqlx.toml和.env,决定连库还是读.sqlx,再按 URL scheme 选驱动;编译期的连接按 URL 缓存在 rustc 进程里,每个 crate 一条,describe 结果本身不缓存。 - 生成的代码:用
cargo expand看展开结果;参数检查是一段永不执行的if false,让 rustc 在参数位置报类型错误;结果是匿名Record,逐列try_get_unchecked再into;列名后缀!、?、: T覆盖推断,: T写错类型运行时不会报错。 - 离线模式与 sqlx.toml:
cargo sqlx prepare是带着环境变量跑一遍cargo check,由宏写.sqlx/query-<hash>.json;离线时怎么读回来;prepare --check为什么能发现 schema 变化而离线构建不能;sqlx.toml的 URL 变量名、类型覆盖和preferred-crates,以及改了它为什么不触发重编译。 - #[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。
💬 关联讨论
发起讨论加载中...