# sql_builder
一个 100% 对齐 [huandu/go-sqlbuilder](https://github.com/huandu/go-sqlbuilder) 设计的 Rust crate。它提供:
- `Args` + `Flavor`:支持 `?`、`$1`、`@p1`、`:1` 等多种占位符策略,并且允许通过 `Flavor` 跟随不同 SQL 方言;
- 完整的各类 Builder:`SelectBuilder`、`InsertBuilder`、`UpdateBuilder`、`DeleteBuilder`、`UnionBuilder`、`CTEBuilder`、`CTEQueryBuilder`、`CreateTableBuilder`,同时内建查、插、改、删、聚合、CTE、Union 和 clone 重用模式;
- `Build`/`Buildf`/`BuildNamed`:支持 `${name}`、`$0`、`$?`、`$$`、`Raw`、`List`、`Tuple` 等语法,并支持嵌套 builder、named arg 重用、literal `$` 等特殊行为;
- `Struct` + `field_mapper`:通过 `macro_rules!` 生成 `FieldMeta`,支持 `db`/`fieldtag`/`fieldopt`/`fieldas`、`with_tag`/`without_tag`、自定义 field mapper(如 snake_case/kebab_case/prefix/suffix)并兼容 `SqlValuer`;
- `Scan` + `ScanCell`:仿照 Go 的 `Addr` 实现数据扫描;
- `interpolate`:为不支持参数化的驱动提供 SQL 插值,涵盖多 flavor 的字符串/数字/日期/布尔等转义;
- `SqlValuer`:支持延迟计算参数,兼容自定义数据源;
- 全部示例/单测对齐 Go:138 条单测 + doc-test,覆盖 README 中的 builder、Struct、CTE、Union、field mapper、命名参数等场景。
## 典型用法
### 创建 SELECT
```rust
use halo::sqlx::select::SelectBuilder;
let mut sb = SelectBuilder::new();
sb.select(["id"]).from(["user"]);
sb.where_([sb.in_("status", [1_i64, 2, 3])]);
let (sql, args) = sb.build();
assert_eq!(sql, "SELECT id FROM user WHERE status IN (?, ?, ?)");
assert_eq!(args.len(), 3);
```
### 嵌套 Builder / Buildf
```rust
use halo::sqlx::builder::buildf;
let mut sb = SelectBuilder::new();
sb.select(["id"]).from(["user"]);
let explain = buildf(
"EXPLAIN %v LEFT JOIN SELECT * FROM banned WHERE state IN (%v, %v)",
[sb.into(), 1_i64, 2_i64],
);
let (sql, _) = explain.build();
assert!(sql.contains("EXPLAIN SELECT id FROM user"));
```
### named 参数
```rust
use halo::sqlx::{
builder::build_named,
modifiers::{SqlNamedArg, raw, list},
};
let mut named = std::collections::HashMap::new();
named.insert("table".to_string(), raw("user"));
named.insert("status".to_string(), list([1_i64, 2, 3]));
named.insert("time".to_string(), SqlNamedArg::new("start", 1_514_458_225_i64).into());
let (sql, args) = build_named(
"SELECT * FROM ${table} WHERE status IN (${status}) AND created_at > ${time}",
named,
)
.build();
assert!(sql.contains("@start"));
```
### Struct ORM + field mapper
```rust
use halo::sqlx::{field_mapper::snake_case_mapper, Struct};
let _= halo::sqlx::field_mapper::set_default_field_mapper_scoped(std::sync::Arc::new(snake_case_mapper));
halo::sqlx::sql_struct! {
impl User {
id: { db: "id", tags: [], omitempty: [], quote: false, as: None },
user_name: { db: "", tags: [], omitempty: [], quote: false, as: None }
}
}
let s = Struct::<User>::new();
let (sql, _) = s.select_from("user").build();
assert!(sql.contains("user.user_name"));
```
### CTE 与 Union
```rust
use halo::sqlx::{cte::with, cte_query::CTEQueryBuilder, select::SelectBuilder};
let mut users_cte = CTEQueryBuilder::new();
let mut query = SelectBuilder::new();
query.select(["id"]).from(["users"]).where_(["name IS NOT NULL"]);
users_cte.table("users", ["id"]).as_(query);
let cte = with([users_cte]);
let mut sb = cte.select(["users.id"]);
sb.from(["users"]);
let (sql, _) = sb.build();
assert!(sql.contains("WITH users"));
```
## 维护与测试
```bash
cargo fmt
cargo clippy --all-targets --all-features -- -D warnings
cargo test
```
## 许可证
MIT