6个版本
0.1.5 | 2024年7月5日 |
---|---|
0.1.4 | 2024年7月4日 |
0.1.3 | 2024年5月23日 |
#10 在 #edge-db
每月下载量 246
在 edgedb-tokio-ext 中使用
17KB
255 行
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)(untagged)]
进行注释。
形状查询
为了避免在编辑您想要反序列化的结构体时总是需要编辑您的查询,我创建了两个宏: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查询,请使用shaped_query!
宏。
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
,但由于没有统一它们的特例,因此存在问题。由于 Transaction
创建的 future 不是 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!()
}
依赖关系
~2.3–4MB
~70K SLoC