2个版本
0.2.9 | 2022年10月18日 |
---|---|
0.2.8 | 2022年7月11日 |
#2332 在 数据库接口
160KB
4K SLoC
qians_xql
用于sqlx的SQL查询构建器。工作正在进行中
目录
基本查询构建
假设您有一个这样的表
CREATE TABLE book(
id INTEGER PRIMARY KEY,
title TEXT NOT NULL,
author TEXT,
lang TEXT,
year SMALLINT
);
CRUD(或ISUD,sql为缩写)将看起来像这样
INSERT
语句。
let book1 = "The Fellowship of the Rings".to_string();
let auth1 = "J. R. R. Tolkien".to_string();
let book2 = "Dune".to_string();
let auth2 = "Frank Herbret".to_string();
let english = "English".to_string();
let values = [
(1_i32, &book1, &auth1, &english, 1954_i16),
(2_i32, &book2, &auth2, &english, 1965_i16),
];
let insert = qians_xql::insert("book", ["id", "title", "author", "lang", "year"])
.values(values)
.returning(["id"]);
assert_eq!(
insert.to_string(),
"INSERT INTO book(id, title, author, lang, year) VALUES \
(1, 'The Fellowship of the Rings', 'J. R. R. Tolkien', 'English', 1954), \
(2, 'Dune', 'Frank Herbret', 'English', 1965) \
RETURNING id",
);
SELECT
语句。
let select = qians_xql::select(["id", "title"])
.from("book")
.filter(qians_xql::or(qians_xql::eq("id", 1), qians_xql::eq("id", 2)))
.order_by(qians_xql::desc("year"));
assert_eq!(
select.to_string(),
"SELECT id, title FROM book WHERE id = 1 OR id = 2 ORDER BY year DESC"
);
UPDATE
语句。
let author = &"Frank Herbert".to_string();
let update = qians_xql::update("book")
.set("author", author)
.filter(qians_xql::eq("id", 2))
.returning(["id"]);
assert_eq!(
update.to_string(),
"UPDATE book SET author = 'Frank Herbert' WHERE id = 2 RETURNING id",
);
DELETE
语句。
let delete = qians_xql::delete("book")
.filter(qians_xql::eq("id", 1))
.returning(["id", "title"]);
assert_eq!(
delete.to_string(),
"DELETE FROM book WHERE id = 1 RETURNING id, title",
);
通配符
在qians_xql::blanket
中定义的特质中存在一些通配实现,以协助查询构建。
在表达式上使用通配符
qians_xql::ops
中定义的大多数expr函数都有qians_xql::blanket::ExprExt
的通配实现方法。
use qians_xql::blanket::ExprExt;
let cond = "year".greater_than(1900).and("year".less_equal(2000));
assert_eq!(cond.to_string(), "year > 1900 AND year <= 2000");
let query = qians_xql::select(["id"]).from("book").filter(cond);
assert_eq!(query.to_string(), "SELECT id FROM book WHERE year > 1900 AND year <= 2000");
看起来很冗长。这是不可避免的,因为使用gt
或le
将与PartialOrd
冲突(即使使用no_implicit_prelude
也无法禁用)。下面的代码将无法编译。
use qians_xql::blanket::ExprExt;
let cond = "year".gt(1900).and("year".le(2000));
一种解决方案是将左侧转换为Expr
或使用表限定列引用。
use qians_xql::expr::Expr;
use qians_xql::blanket::ExprExt;
let year = Expr::from("year");
let qualified = ("book", "year");
let cond = year.gt(1900).and(qualified.le(2000));
assert_eq!(cond.to_string(), "year > 1900 AND book.year <= 2000");
在表表达式上使用通配符
join
函数族有一些通配实现。
use qians_xql::blanket::ExprExt;
use qians_xql::blanket::TableExprExt;
let table = "book".join("category", ("book", "category_id").eq(("category", "id")));
assert_eq!(table.to_string(), "book JOIN category ON book.category_id = category.id");
在SELECT
和VALUES
语句上使用通配符
只有SELECT
和VALUES
语句可以使用UNION
函数族。
use qians_xql::blanket::ResultExt;
let query = qians_xql::select([1, 2]).union(qians_xql::values([(3, 4)]));
assert_eq!(query.to_string(), "SELECT 1, 2 UNION VALUES (3, 4)");
如果您好奇,ResultExt
的名字来源于qians_xql::stmt::result::Result
,这是一个仅包含Select
和Values
枚举的类型。为什么是Result
?因为命名很难,而且它在Stmt
枚举定义中看起来很好。
enum Stmt {
Insert,
Select,
Update,
Delete,
Values,
Binary,
Result, // See!? Exactly 6 characters! Perfectly balanced as all things should be!
}
执行
要执行这些查询,启用sqlx
功能和以下之一:postgres
、mysql
或sqlite
功能。
#[derive(sqlx::FromRow)]
struct Output {
id: i32,
title: String,
}
#[cfg(feature = "postgres")]
async fn execute(pool: sqlx::Pool::<sqlx::Postgres>) -> Result<(), sqlx::Error> {
// sqlx::query(..).fetch_all
let query = qians_xql::select(["id", "title"]).from("book");
let rows = qians_xql::exec::fetch_all(query, &pool).await?;
// sqlx::query_as(..).fetch_all
let query = qians_xql::select(["id", "title"]).from("book");
let rows: Vec<Output> = qians_xql::exec::fetch_all_as(query, &pool).await?;
// sqlx::query_scalar(..).fetch_all
let query = qians_xql::select(["id"]).from("book");
let rows: Vec<i32> = qians_xql::exec::fetch_all_scalar(query, &pool).await?;
// or in blanket form
use qians_xql::blanket::StmtExt;
let rows = qians_xql::select(["id", "title"])
.from("book")
.fetch_all(&pool).await?;
let rows: Vec<Output> = qians_xql::select(["id", "title"])
.from("book")
.fetch_all_as(&pool)
.await?;
let rows: Vec<i32> = qians_xql::select(["id"])
.from("book")
.fetch_all_scalar(&pool).await?;
Ok(())
}
可用变体包括:fetch_one
、fetch_all
、fetch_optional
,分别带有_as
、_scalar
或无后缀。
关于str
和String
的说明
您可能在上面的示例中注意到多次使用&"text".to_string()
。这是因为&str
将转换为标识符,而&String
将转换为文本字面量。
依赖关系
~0–14MB
~184K SLoC