3 个版本
新版本 0.1.2 | 2024 年 8 月 27 日 |
---|---|
0.1.1 | 2024 年 8 月 26 日 |
0.1.0 | 2024 年 8 月 25 日 |
311 在 数据库接口 中排名
每月 180 次下载
49KB
780 行
edgedb_codegen
从您的 EdgeDB 架构和内联查询生成完全类型的 Rust 代码。
安装
要安装 edgedb_codegen
crate,可以使用以下命令。
cargo add edgedb_codegen
或者直接将以下内容添加到您的 Cargo.toml
文件中。
edgedb_codegen = "0.1.0" # replace with the latest version
按照快速入门指南操作,确保您的 edgedb 实例正在运行。该宏依赖于运行的 edgedb
实例来解析提供的查询字符串输出。
用法
当使用 edgedb
时,您通常需要编写查询并为输入和输出提供类型。您的代码仅在运行时进行检查,这增加了错误和故障的风险。
幸运的是,edgedb
有一种类型化的查询语言,可以在编译时将其转换为类型并查询其正确性。
内联查询
use edgedb_codegen::edgedb_query;
use edgedb_errors::Error;
use edgedb_tokio::create_client;
// Creates a module called `simple` with a function called `query` and structs
// for the `Input` and `Output`.
edgedb_query!(
simple,
"select { hello := \"world\", custom := <str>$custom }"
);
#[tokio::main]
async fn main() -> Result<(), Error> {
let client = create_client().await?;
let input = simple::Input::builder().custom("custom").build();
// For queries the following code can be used.
let output = simple::query(&client, &input).await?;
Ok(())
}
上面的宏生成以下代码
pub mod simple {
use ::edgedb_codegen::exports as e;
#[doc = r" Execute the desired query."]
#[cfg(feature = "query")]
pub async fn query(
client: &e::edgedb_tokio::Client,
props: &Input,
) -> core::result::Result<Output, e::edgedb_errors::Error> {
client.query_required_single(QUERY, props).await
}
#[doc = r" Compose the query as part of a larger transaction."]
#[cfg(feature = "query")]
pub async fn transaction(
conn: &mut e::edgedb_tokio::Transaction,
props: &Input,
) -> core::result::Result<Output, e::edgedb_errors::Error> {
conn.query_required_single(QUERY, props).await
}
#[derive(Clone, Debug, e :: typed_builder :: TypedBuilder)]
#[cfg_attr(feature = "serde", derive(e::serde::Serialize, e::serde::Deserialize))]
#[cfg_attr(feature = "query", derive(e::edgedb_derive::Queryable))]
pub struct Input {
#[builder(setter(into))]
pub custom: String,
}
impl e::edgedb_protocol::query_arg::QueryArgs for Input {
fn encode(
&self,
encoder: &mut e::edgedb_protocol::query_arg::Encoder,
) -> core::result::Result<(), e::edgedb_errors::Error> {
let map = e::edgedb_protocol::named_args! { "custom" => self . custom . clone () , };
map.encode(encoder)
}
}
#[derive(Clone, Debug, e :: typed_builder :: TypedBuilder)]
#[cfg_attr(feature = "serde", derive(e::serde::Serialize, e::serde::Deserialize))]
#[cfg_attr(feature = "query", derive(e::edgedb_derive::Queryable))]
pub struct Output {
#[builder(setter(into))]
pub hello: String,
#[builder(setter(into))]
pub custom: String,
}
#[doc = r" The original query string provided to the macro. Can be reused in your codebase."]
pub const QUERY: &str = "select { hello := \"world\", custom := <str>$custom }";
}
查询文件
在您的 crate 的 queries
目录中定义一个查询文件,名为 select_user.edgeql
。
# queries/select_user.edgeql
select User {
name,
bio,
slug,
} filter .slug = <str>$slug;
然后使用 edgedb_query
宏导入查询。
use edgedb_codegen::edgedb_query;
use edgedb_errors::Error;
use edgedb_tokio::create_client;
// Creates a module called `select_user` with public functions `transaction` and
// `query` as well as structs for the `Input` and `Output`.
edgedb_query!(select_user);
#[tokio::main]
async fn main() -> Result<(), Error> {
let client = create_client().await?;
// Generated code can be run inside a transaction.
let result = client
.transaction(|mut txn| {
async move {
let input = select_user::Input::builder().slug("test").build();
let output = select_user::transaction(&mut txn, &input).await?;
Ok(output)
}
})
.await?;
Ok(())
}
未来工作
此 crate 仍在早期开发阶段,并且还有几个功能尚未实现。
缺少类型
目前不支持以下类型
enum
- 目前所有枚举都表示为字符串。MultiRange
- 如果使用多范围,宏将引发恐慌。
枚举
目前所有枚举都表示为字符串。
为了支持完整的枚举生成,需要将 edgedb-protocol
crate 更新为使用 更新 到 二进制协议 2.0。在当前的 1.0 版本中,枚举描述符返回时不包含名称属性。
一旦实现,该宏将能够生成正确的代码。
然而,最终用户可能不希望为每个生成的查询模块使用多个枚举,因为这会破坏共享。为了解决这个问题,应该有一个宏来生成所有其他模块共用的共享类型。
// lib.rs
use edgedb_codegen::generate_shared_types;
generate_shared_types!(); // exports the shared types to the `edb` module.
MultiRange
这些类型目前没有通过 edgedb-protocol
导出,所以如果它们在新协议中仍然被支持,应该在 edgedb-protocol
crate 中通过 PR 添加。
配置
目前一切都是硬编码的,宏不可配置。
应添加以下配置选项
- 输入结构体名称(可选) - 默认为
Input
。 - 输出结构体名称(可选) - 默认为
Output
。 - 查询函数名称(可选) - 默认为
query
。 - 事务函数名称(可选) - 默认为
transaction
。 - 查询默认位置(可选) - 默认为
queries
。 - 共享类型默认 crate 导出名称(可选) - 默认为
edb
。 - 默认
edgedb
实例(可选) - 默认为$EDGEDB_INSTANCE
。 - 默认
edgedb
分支(可选) - 默认为$EDGEDB_BRANCH
。
可能应该从 Cargo.toml
文件中读取这些值并手动解析,以防止解析文件时的降速。
LSP 解析
目前宏依赖于运行中的 edgedb 实例来解析查询字符串。
一旦为 edgedb 创建了 LSP,就有意义从使用字符串切换到使用内联 edgedb 查询。
use edgedb_codegen::edgedb_query;
edgedb_query!(
example,
select User {**}
);
CLI
创建一个 edgedb_codegen_cli
crate,它支持将类型代码生成到 rust 文件中,而不是内联查询。这对于大型项目很有用,可以防止在每次更改/构建时都重新编译查询。
依赖项
~17–29MB
~572K SLoC