3 个版本
0.1.0 | 2024年5月23日 |
---|---|
0.1.0-alpha.5 | 2023年7月2日 |
0.1.0-alpha.4 | 2023年6月7日 |
#2304 在 数据库接口
149 每月下载量
22KB
276 行
bluejay-typegen
bluejay-typegen
从 GraphQL 架构和可执行文档中生成类型。
贡献
tests/validation_test.rs
使用 trybuild
,这是代码在 tests/validation_cases/error
中编译错误的基本快照测试。要覆盖快照,在运行 cargo test
时使用 TRYBUILD=overwrite
环境变量。
lib.rs
:
bluejay-typegen
是一个用于从 GraphQL 架构和查询生成 Rust 类型的 crate。
用法
typegen
宏从 GraphQL 架构和任意数量的查询生成 Rust 类型。该宏必须装饰一个模块,并且该模块必须包含对架构中定义的每个自定义标量(custom scalar)的类型别名。架构中所有共享的类型(输入对象、枚举)都将在模块中生成。
参数
该宏接受一个位置参数,后跟一系列可选的命名参数。位置参数可以是字符串字面量,指向包含 SDL 格式架构的文件(相对于使用宏的 crate 的 Cargo.toml
中的路径),或者直接在宏调用中定义架构的 DSL 代码,用方括号括起来。可选的命名参数包括
borrow
:一个布尔值,表示生成的类型是否应从输入 JSON 值借用字符串而不是拥有它们。默认为false
。codec
:指定用于序列化和反序列化值的编解码器的字符串字面量。必须是以下之一:"serde"
或"miniserde"
。当启用serde
功能时,默认为"serde"
,否则当启用miniserde
功能时,默认为"miniserde"
。当使用miniserde
时,borrow
必须为false
,因为miniserde
不支持借用字符串。
查询
在定义模式定义的模块内部,可以定义任何数量的可执行文档的子模块。可以通过用 #[query(...)]
装饰子模块来实现。其中参数遵循宏的位置参数的相同约定。对于查询文档中的每个操作和片段定义,都会生成相应的 Rust 类型。如果定义了匿名操作,类型名为 Root
。有关更多信息,请参阅 类型路径模式。
示例
#[bluejay_typegen::typegen([
scalar UnsignedInt
enum Position {
WING
CENTRE
DEFENCE
}
type Skater {
name: String!
position: Position!
age: UnsignedInt!
stats: [SkaterStat!]!
}
type SkaterStat {
goals: UnsignedInt!
}
type Goalie {
name: String!
age: UnsignedInt!
stats: [GoalieStat!]!
}
type GoalieStat {
wins: UnsignedInt!
}
union Player = Skater | Goalie
type Query {
player: Player!
}
], borrow = true)]
mod schema {
type UnsignedInt = u32;
#[query([
query Player {
player {
__typename
...on Skater {
name
age
position
stats { goals }
}
...on Goalie {
name
age
stats { wins }
}
}
}
])]
pub mod query {}
}
let value = serde_json::json!({
"player": {
"__typename": "Skater",
"name": "Auston Matthews",
"age": 25,
"position": "CENTRE",
"stats": [
{
"goals": 60
},
],
},
}).to_string();
let result: schema::query::Player = serde_json::from_str(&value).expect("Error parsing value");
assert_eq!(
schema::query::Player {
player: schema::query::player::Player::Skater {
name: "Auston Matthews".into(),
age: 25,
position: schema::Position::Centre,
stats: vec![schema::query::player::player::skater::Stats { goals: 60 }],
},
},
result,
);
限制
- 查询不能包含具有相同名称的操作定义
- 模式模块必须包含每个自定义标量类型的一个别名,以便在生成的 Rust 类型中使用
- 在对象类型的范围内,选择集不得包含任何内联片段,并且必须
- 至少包含一个字段选择,或者
- 包含一个片段扩展
- 在接口类型的范围内,选择集不得包含任何内联片段,并且必须
- 至少包含一个字段选择,或者
- 包含一个片段扩展,其中片段扩展的目标类型是接口类型本身或接口类型实现的接口
- 在联合类型的范围内,选择集必须
- 包含一个未命名的字段选择作为集合中的第一个选择,并且没有其他字段选择,并且
- 不包含任何片段扩展,并且
- 不包含针对联合类型中任何对象类型的多个内联片段,并且
- 不包含针对不在联合类型中的类型的内联片段
类型路径模式
生成的 Rust 类型中给定类型的路径由以下规则确定
- 如果类型是自定义标量、枚举或输入类型,则路径为
"schema_module"
。例如,上述示例中的"Position"
枚举具有路径"schema_module"
。 - 如果类型是操作根类型,则路径为
"query_module"
。例如,上述示例中的"Player"
查询根类型具有路径"query_module"
。 - 如果类型是匿名操作根类型,路径为
schema_module::query_module::Root
- 如果类型是嵌套对象类型,路径位于父对象类型的路径之下,例如
schema_module::query_module::operation_name::TypeName
。例如,上述示例中Player
Rust 枚举类型对应于player
字段的路径为schema::query::player::Player
。而Stats
Rust 结构体类型对应于Player
枚举中Skater
分支的stats
字段的路径为schema::query::player::player::skater::Stats
。 - 如果类型是片段定义,路径为
schema_module::query_module::FragmentName
,所有嵌套类型都遵循操作类型的相同模式,例如在schema_module::query_module::fragment_name::TypeName
。
依赖项
~5.5MB
~74K SLoC