6 个版本
| 0.1.5 | 2024 年 7 月 5 日 |
|---|---|
| 0.1.4 | 2024 年 7 月 4 日 |
| 0.1.3 | 2024 年 5 月 23 日 |
#442 在 Rust 模式
每月 233 次下载
13KB
155 行
edgedb-tokio-ext
当与 edgedb-rust 一起工作时,这是一个常见辅助特质、宏和函数的库
Serde 扩展
此库在 edgedb_tokio::Client 和 edgedb_tokio::Transaction 上分别实现了 SerdeClientExt 和 SerdeTrxExt。在 Transaction 中,需要可变引用来运行客户端函数,并且 futures 也不是 Send。要使用此特质并无缝地将 edgedb 查询返回值反序列化到您的 serde 结构中,请导入特质。
use edgedb_tokio_ext::SerdeClientExt;
use serde::Deserialize;
use uuid::Uuid;
#[derive(Deserialize, Debug)]
struct User {
id: Uuid,
name: Name,
age: i64,
org: Option<Organization>,
}
#[derive(Deserialize, Debug)]
struct Name {
first: String,
last: String,
}
#[derive(Deserialize, Debug)]
struct Organization {
id: Uuid,
name: String,
}
#[tokio::test]
async fn test_derive_project() {
let edgedb_client = edgedb_tokio::create_client().await.unwrap();
let query = "
with
org := (insert Organization {
name := 'Edgedb'
}),
user := (insert User {
name := (first := 'Lurian', last := 'Warlock'),
age := 26,
org := org
})
select user { ** }
";
let user = edgedb_client
.query_required_single_serde::<User>(query, &())
.await
.unwrap();
assert_eq!(user.name.first, "Lurian");
}
提示:当您有一个可以返回抽象类型的不同子类型的多态查询时,这非常有效,只需使用一个 enum 并用 #[serde)] 注释即可。
有形状的查询
为了避免在编辑您想要反序列化的结构时必须始终编辑您的查询,我创建了两个宏:Shape 和 shaped_query。
#[derive(Shape, Queryable, Debug)]
struct User {
id: Uuid,
#[shape(exp = ".name.first")]
first_name: String,
#[shape(exp = ".name.last")]
last_name: String,
#[shape(alias = "age")]
age_value: i64,
#[shape(alias = "org", nested)]
organization: Option<Organization>,
}
#[derive(Shape, Queryable, Debug)]
struct Organization {
id: Uuid,
name: String,
}
该宏负责创建一个返回包含字段选择体的 &'static str 的 shape 函数。宏展开也是递归的,并且对 Organization 的投影将应用于 User 中的 organization 字段。
要使用 shaped_query! 宏将字段选择合并到 EdgeDB 查询中
let edgedb_client = edgedb_tokio::create_client().await.unwrap();
let query = shaped_query!(
"
with
org := (insert Organization {
name := 'Edgedb'
}),
user := (insert User {
name := (first := 'Lurian', last := 'Warlock'),
age := 26,
org := org
})
select user { shape::User }
"
);
let user = edgedb_client
.query_required_single::<User, _>(query, &())
.await
.unwrap();
assert_eq!(user.first_name, "Lurian");
宏属性相当简单
nested如果您的字段需要扩展子类型,请使用此属性。exp这个属性允许您传递赋值语句的右侧,它与alias互斥。您可以在表达式中构建一个 命名元组,然后由Queryable结构体获取,或者直接跟随一个链接和属性,解构命名元组字段等等。如何使用它取决于您。alias如果您的结构体字段和边缘数据库类型字段具有不同的名称,请使用此属性。它是exp = ".fieldname"的缩写。
事务变体
由于没有统一它们的特例,因此存在一个问题,代码应接受 &edgedb_tokio::Client 或 &edgedb_tokio::Transaction,因为事务创建的未 Send 的未来,并且还要求使用可变引用,这会使使用此类特例的函数在用于 Client 而不是 Transaction 时相当有限。我仍然认为此类特例具有价值,然而为了满足我的当前需求,我创建了 tx_variant 宏,该宏创建一个与原始名称相同,后跟 _tx 的函数,该函数接受 &mut Transaction 而不是 &Client。这个宏仍然是一个思想实验,例如,内函数体不会用其 tx 变体替换对其他数据库函数的调用(尚未如此),但是它仍然可以减少重复代码。
#[tx_variant]
async fn sample_db_function(id: &Uuid, client: &edgedb_tokio::Client) {
client.query_required_single_json("", &(id,)).await.unwrap();
todo!()
}
生成
async fn sample_db_function_tx(id: &Uuid, client: &mut edgedb_tokio::Transaction) {
client.query_required_single_json("", &(id,)).await.unwrap();
todo!()
}
依赖关系
~19–32MB
~607K SLoC