#edge-db #tokio #macro #derive #ext #query #edgedb-tokio-ext

进程宏 edgedb-tokio-ext-derive

为edgedb-tokio-ext提供派生宏

6个版本

0.1.5 2024年7月5日
0.1.4 2024年7月4日
0.1.3 2024年5月23日

#10#edge-db

Download history 133/week @ 2024-05-02 79/week @ 2024-05-09 149/week @ 2024-05-16 161/week @ 2024-05-23 3/week @ 2024-05-30 8/week @ 2024-06-06 3/week @ 2024-06-13 228/week @ 2024-07-04 5/week @ 2024-07-11 2/week @ 2024-07-18 11/week @ 2024-07-25

每月下载量 246
edgedb-tokio-ext 中使用

MIT 许可证

17KB
255

edgedb-tokio-ext

edgedb-rust一起工作的常见辅助特质、宏和函数的库

Serde扩展

此库在edgedb_tokio::Clientedgedb_tokio::Transaction上分别实现了SerdeClientExtSerdeTrxExt。在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)]进行注释。

形状查询

为了避免在编辑您想要反序列化的结构体时总是需要编辑您的查询,我创建了两个宏:Shapeshaped_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 strshape函数。宏展开也是递归的,并将对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