#sql-query #sql #query #sqlite #postgresql

sql_query_builder

以简单和可组合的方式编写SQL查询

28个版本 (10个稳定版)

2.3.0 2024年7月21日
2.1.0 2023年12月11日
2.0.0 2023年9月30日
1.1.4 2023年5月30日
0.10.5 2022年7月27日

#74 in 数据库接口

Download history 603/week @ 2024-05-03 481/week @ 2024-05-10 586/week @ 2024-05-17 647/week @ 2024-05-24 618/week @ 2024-05-31 550/week @ 2024-06-07 526/week @ 2024-06-14 666/week @ 2024-06-21 587/week @ 2024-06-28 528/week @ 2024-07-05 464/week @ 2024-07-12 585/week @ 2024-07-19 718/week @ 2024-07-26 543/week @ 2024-08-02 519/week @ 2024-08-09 693/week @ 2024-08-16

2,587 每月下载量
3 个Crates中使用了(b 2 直接)

MIT 许可证

165KB
2.5K SLoC

以简单和可组合的方式编写SQL查询。

主要目标是找到编写惯用SQL查询和管理混合条件语句的复杂查询组合场景之间的最佳平衡。

快速入门

use sql_query_builder as sql;

let mut select = sql::Select::new()
  .select("id, login")
  .from("users")
  .where_clause("login = $1");

let is_admin = true;

if is_admin {
  select = select.where_clause("is_admin = true");
}

let query = select.as_string();

println!("{}", query);

输出

SELECT id, login FROM users WHERE login = $1 AND is_admin = true

功能标志

SQL Query Builder附带以下可选功能

  • postgresql 启用Postgres语法
  • sqlite 启用SQLite语法

您可以使用以下功能

# Cargo.toml

sql_query_builder = { version = "2.x.x", features = ["postgresql"] }

工作原理

简单来说,该库有一个API,允许您以类似于纯SQL编写的查询风格编写动态查询,结果是与Rust和SQL都符合代码习惯的代码。此外,库不会尝试理解您在参数中写入的内容,这在某种程度上是好的,因为它减少了生成SQL查询的冗余,相比之下,调试通常更困难,可能会出现一些愚蠢的错误,库有一个debug()方法,它提供了良好的输出以最大限度地减少调试复杂查询的努力。

更技术地说,对同一子句的连续调用将累积值,并尊重调用顺序,两个select生成相同的SQL查询。

use sql_query_builder as sql;

let select = sql::Select::new()
  .select("id, login");

let select = sql::Select::new()
  .select("id")
  .select("login");

limitoffset这样的方法将覆盖前一个值,两个select是等效的

# #[cfg(any(feature = "postgresql", feature = "sqlite"))]
# {
use sql_query_builder as sql;

let select = sql::Select::new()
  .limit("1000")
  .limit("123");

let select = sql::Select::new()
  .limit("123");
# }

库忽略子句之间的顺序,因此两个select将生成相同的查询

use sql_query_builder as sql;

let select = sql::Select::new()
  .select("id, login")
  .from("users")
  .where_clause("login = $1");

let select = sql::Select::new()
  .from("users")
  .where_clause("login = $1")
  .select("id, login");

您可以通过修改select来条件性地添加子句

use sql_query_builder as sql;

let mut select = sql::Select::new()
  .select("id, login")
  .from("users")
  .where_clause("login = $1");

let should_includes_address = true;

if should_includes_address {
  select = select.inner_join("addresses on user.login = addresses.owner_login");
}

组合

组合对于编写复杂查询非常受欢迎,这个功能使得库更加出色

use sql_query_builder as sql;

fn project(select: sql::Select) -> sql::Select {
  select
    .select("u.id, u.name as user_name, u.login")
    .select("a.name as addresses_name")
    .select("o.name as product_name")
}

fn relations(select: sql::Select) -> sql::Select {
  select
    .from("users u")
    .inner_join("addresses a ON a.user_login = u.login")
    .inner_join("orders o ON o.user_login = u.login")
}

fn conditions(select: sql::Select) -> sql::Select {
  select
    .where_clause("u.login = $1")
    .where_clause("o.id = $2")
}

fn as_string(select: sql::Select) -> String {
  select.as_string()
}

let query = Some(sql::Select::new())
  .map(project)
  .map(relations)
  .map(conditions)
  .map(as_string)
  .unwrap();

println!("{query}");

输出(缩进以提高可读性)

SELECT u.id, u.name as user_name, u.login, a.name as addresses_name, o.name as product_name
FROM users u
INNER JOIN addresses a ON a.user_login = u.login
INNER JOIN orders o ON o.user_login = u.login
WHERE u.login = $1 AND o.id = $2

原始查询

您可以使用原始方法来访问一些难以用Select语法重写的边缘情况。 select.raw()方法将把您定义的任何SQL放在输出的顶部

use sql_query_builder as sql;

let raw_query = "\
  select u.id as user_id, addr.* \
  from users u \
  inner join addresses addr on u.login = addr.owner_login\
";
let select = sql::Select::new()
  .raw(raw_query)
  .where_clause("login = $1");

为了更精确地使用,您可以使用 select.raw_before()select.raw_after()

use sql_query_builder as sql;

let raw_query = "\
  from users u \
  inner join addresses addr on u.login = addr.owner_login\
";
let select = sql::Select::new()
  .select("u.id as user_id, addr.*")
  .raw_before(sql::SelectClause::Where, raw_query)
  .where_clause("login = $1");
use sql_query_builder as sql;

let raw_query = "\
  from users u \
  inner join addresses addr on u.login = addr.owner_login\
";
let select = sql::Select::new()
  .select("u.id as user_id, addr.*")
  .raw_after(sql::SelectClause::Select, raw_query)
  .where_clause("login = $1");

调试查询

有时直接打印查询构建器的当前状态会更加方便。为此,在任何地方添加 .debug() 方法。以下示例中,由于在子句之前添加了 debug,因此 where 子句将不会被打印。

use sql_query_builder as sql;

let mut select = sql::Select::new()
  .select("id, login")
  .from("users")
  .debug()
  .where_clause("login = $1");

打印到标准输出

-- ------------------------------------------------------------------------------
SELECT id, login
FROM users
-- ------------------------------------------------------------------------------

有关更多构建器,如 文档 中的 InsertUpdateDelete,请参阅。

无运行时依赖