# 派生字段 有时两个字段有一样的查询逻辑,仅仅是输出的类型不同,在 `async-graphql` 中,你可以为它创建派生字段。 在以下例子中,你已经有一个`duration_rfc2822`字段输出`RFC2822`格式的时间格式,然后复用它派生一个新的`date_rfc3339`字段。 ```rust struct DateRFC3339(chrono::DateTime); struct DateRFC2822(chrono::DateTime); #[Scalar] impl ScalarType for DateRFC3339 { fn parse(value: Value) -> InputValueResult { ... } fn to_value(&self) -> Value { Value::String(self.0.to_rfc3339()) } } #[Scalar] impl ScalarType for DateRFC2822 { fn parse(value: Value) -> InputValueResult { ... } fn to_value(&self) -> Value { Value::String(self.0.to_rfc2822()) } } impl From for DateRFC3339 { fn from(value: DateRFC2822) -> Self { DateRFC3339(value.0) } } struct Query; #[Object] impl Query { #[graphql(derived(name = "date_rfc3339", into = "DateRFC3339"))] async fn duration_rfc2822(&self, arg: String) -> DateRFC2822 { todo!() } } ``` 它将呈现为如下GraphQL: ```graphql type Query { duration_rfc2822(arg: String): DateRFC2822! duration_rfc3339(arg: String): DateRFC3339! } ``` ## 包装类型 因为 [孤儿规则](https://doc.rust-lang.org/book/traits.html#rules-for-implementing-traits),以下代码无法通过编译: ``` impl From> for Vec { ... } ``` 因此,你将无法为现有的包装类型结构(如`Vec`或`Option`)生成派生字段。 但是当你为 `T` 实现了 `From` 后,你可以为 `Vec` 实现 `From>`,为 `Option` 实现 `From>`. 使用 `with` 参数来定义一个转换函数,而不是用 `Into::into`。 ### Example ```rust #[derive(Serialize, Deserialize, Clone)] struct ValueDerived(String); #[derive(Serialize, Deserialize, Clone)] struct ValueDerived2(String); scalar!(ValueDerived); scalar!(ValueDerived2); impl From for ValueDerived2 { fn from(value: ValueDerived) -> Self { ValueDerived2(value.0) } } fn option_to_option>(value: Option) -> Option { value.map(|x| x.into()) } #[derive(SimpleObject)] struct TestObj { #[graphql(derived(owned, name = "value2", into = "Option", with = "option_to_option"))] pub value1: Option, } ```