5个版本
新版本 0.0.5 | 2024年8月13日 |
---|---|
0.0.4 | 2024年5月3日 |
0.0.3 | 2023年5月4日 |
0.0.2 | 2022年1月28日 |
0.0.1 | 2021年12月20日 |
#851 in 数据库接口
63KB
1.5K SLoC
Compact SQL
一个简单的宏,允许编写Postgres的SQL查询,这些查询将在编译时进行压缩(并可选项地检查)。
依赖项
[dependencies]
compact_sql = "0.0.5"
漂亮的错误
如果可以使用指向具体错误范围的指针获得更好的错误,请使用 pretty-errors
功能(需要不稳定Rust版本)。
[dependencies]
compact_sql = { version = "0.0.5", features = ["pretty-errors"] }
使用Compact SQL
仅生成SQL字符串
use compact_sql::pg_sql;
fn main() {
let sql = pg_sql! {
SELECT
relname,
relnamespace,
format("%I", oid),
FROM
pg_catalog.pg_class
WHERE
oid = {var_oid}::oid
};
assert_eq!(
sql,
"SELECT relname,relnamespace,format('%I',oid)FROM pg_catalog.pg_class WHERE oid=$1::oid"
);
}
注意!关键字之间允许有空格(对于VCS更方便),花括号中的命名参数将被替换为Postgres编号参数(相同名称具有相同编号)。
如"SELECT"、"AS"等常见关键字(作为警告)需要大写。
生成带SQL参数的SQL字符串和结构体
宏将Postgres的"命名参数"替换为编号参数,合理地创建具有与参数名称相同的属性名称的结构体。此外,使用Rust的类型轻松约束这些参数。
use compact_sql::pg_sql;
pg_sql! {
impl OidFromPgClass {
SELECT
oid,
relkind,
FROM
pg_catalog.pg_class
WHERE
relname = {name: String}
AND
relnamespace = {nsp: u32}
}
}
fn main() {
let name: String = "pg_attribute".to_string();
let params = OidFromPgClass {
nsp: &11,
name: &name,
};
assert_eq!(OidFromPgClass::PARAM_NAMES, &["name", "nsp"]);
assert_eq!(
OidFromPgClass::SQL_TEXT,
concat!(
"-- OidFromPgClass\n",
"SELECT oid,relkind FROM pg_catalog.pg_class WHERE relname=$1 AND relnamespace=$2",
),
);
assert_eq!(params.params().len(), 2);
}
生成带SQL参数的结构体和特性实现
此库可以为想要构建与生成的结构体一起工作的库(或内部函数)的人生成特性实现体。并非所有用户结构体都设计为公开,因此生成的特性实现不会在公共crate中引用。相反,从本地作用域使用特性名称。但是,您仍然可以使用来自公共 compact_sql_traits
crate的特性。
您可以指定预期的行数,并根据需要使用不同的特性。此外,您必须声明返回行类型。您可以使用 PgResultRow
derive宏来生成必要的实现。
use compact_sql::{pg_sql, PgResultRow};
use compact_sql_traits::*;
use futures_util::{pin_mut, StreamExt, TryStreamExt};
use tokio_postgres::Client;
type PgResult<T> = Result<T, tokio_postgres::Error>;
#[derive(Debug, PgResultRow)]
struct PgClassItem {
relname: String,
relnamespace: u32,
}
#[derive(Debug)]
enum QueriesId {
GetPgClassItem,
}
pg_sql! {
// You can add container attributes like derive to the generated struct:
#[derive(Debug)]
impl QueriesId::GetPgClassItem for ?PgClassItem {
SELECT
relname,
relnamespace,
FROM
pg_catalog.pg_class
WHERE
oid = {class_oid}
}
}
async fn query_opt<Q: QueryMaybeOne>(db: &Client, params: Q) -> PgResult<Option<Q::ResultRow>>
where <Q as QueryMaybeOne>::SqlIdType: std::fmt::Debug
{
dbg!(Q::SQL_ID);
let query_result = db
.query_raw(Q::SQL_TEXT, params.params())
.await?;
let future = query_result.map_ok(Q::ResultRow::from_row);
pin_mut!(future);
Ok(match future.next().await {
None => None,
Some(v) => Some(v??),
})
}
async fn func(db: &Client) -> PgResult<()> {
let name: String = "pg_attribute".to_string();
let params = GetPgClassItem {
class_oid: &11,
};
let res: Option<PgClassItem> = query_opt(db, params).await?;
dbg!(res);
Ok(())
}
您可以在 test_trait_impl.rs
中查看更多示例。
测试SQL查询
如果您想检查查询(通过"准备"),您可以定义DBMS的ENV
TEST_PG_HOST
TEST_PG_PORT
(可选;默认:5432)TEST_PG_USER
(可选;默认:"postgres")TEST_PG_PASS
(可选;默认:"")TEST_PG_DATB
许可证
许可以下任一项
- Apache License,版本2.0,(LICENSE-APACHE 或 http://www.apache.org/licenses/LICENSE-2.0)
- 麻省理工学院许可证(LICENSE-MIT 或 http://opensource.org/licenses/MIT)
任选其一。
贡献
除非您明确声明,否则根据 Apache-2.0 许可证定义的,您有意提交以包含在作品中的任何贡献,将按照上述方式双重许可,不附加任何额外条款或条件。
依赖
~7–16MB
~226K SLoC