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