Rust in Everything
基于 sea-query 1.0.2

sea-query

sea-orm 自己不拼 SQL。Select<E>、Insert<A> 这些类型里装的是 sea-query 的语句(SelectStatement、InsertStatement…),到 ConnectionTrait::query_one 这一步才调 build,选一个方言写成字符串和参数,最后交给 sqlx。这一部分讲 sea-query 1.0.2 和 sea-query-sqlx 0.9.1 里查询主线经过的三段:语句树、把树写成 SQL 的 QueryBuilder、把参数绑到 sqlx 的 SqlxValues。相关源码:src/query/ 约 8.2k 行(其中 select.rs 3k,2k 行是文档注释里的例子),src/backend/query_builder.rs 2.1k,backend/postgres/ 约 1.6k,sea-query-sqlx/src/sqlx_postgres.rs 387 行。

  1. 语句是一棵树:四种语句的字段就是 SQL 的各个子句;所有表达式都是一个 Expr 枚举(1.0 起 SimpleExpr 只是它的别名);and_where 和 cond_where 走同一条路,多次调用总是用 AND 连起来;DynIden 是提前渲染好的字符串;语句里没有方言。
  2. QueryBuilder 与参数:build 和 to_string 跑的是同一套 prepare_*,区别只在 SqlWriter::push_param;LIMIT / OFFSET 也是参数,Expr::cust、Order::Field、空条件的 TRUE / FALSE 直接写进 SQL;to_string 用 E'...' 转义字符串、双写标识符里的 ",但输出丢了参数类型,只适合看。
  3. 绑到 sqlx:sea-orm 的 Statement 经 sqlx::query_with(AssertSqlSafe(sql), SqlxValues(values)) 交给 sqlx;IntoArguments 按 Value 分支选 Rust 类型,None 也带着类型(Value::Int(None) 在 Parse 里是 OID 23);含 NULL 元素的数组和超过 i64::MAX 的 u64 会在这里 panic。
flowchart TB
  sel["Select E"] --> tree["SelectStatement 语句树"]
  tree -->|"build(Postgres)"| qb[PostgresQueryBuilder]
  qb --> sqlv["SQL 带 $N + Values"]
  sqlv --> stmt["sea-orm Statement"]
  stmt --> bind["SqlxValues 绑参数"]
  bind --> sqlx["sqlx::query_with"]

Select<E> 自己的 API(filter、order_by、limit)在 04 查询;列上的 eq / is_in 怎么产出 Expr、Value 各分支是什么,在列与值。参数到了 sqlx 之后怎么编码、Parse / Bind 怎么发,看 sqlx 卷的类型和扩展查询协议与语句缓存。

💬 关联讨论

发起讨论
加载中...