Async Graphql InputObject中sqlx Json类型的InputType trait实现问题
问题:Async Graphql中sqlx::Json无法派生InputObject
在使用Async Graphql框架时,模型中使用sqlx的Json类型进行普通API操作正常,但为RegisterInput结构体派生InputObject宏时,出现sqlx::types::Json<Meta>未实现InputType trait的错误。
正常代码(无报错)
#[derive(Serialize, Deserialize, Debug, Clone, sqlx::Type)] #[sqlx(transparent)] pub struct Meta(Map<String, Value>); scalar!(Meta); #[derive(Debug, Serialize, Deserialize, Clone, FromRow, SimpleObject)] pub struct User { #[serde(skip_serializing)] #[graphql(skip)] pub id: Uuid, pub name: String, pub email: String, #[serde(skip_serializing)] #[graphql(skip)] pub password: String, #[serde(skip_serializing)] #[graphql(skip)] pub meta: Json<Meta>, pub created_at: DateTime<Utc>, pub updated_at: DateTime<Utc>, }
报错代码
#[derive(Debug, Deserialize, Validate, InputObject)] pub struct RegisterInput { #[validate(length(min = 4, max = 10))] pub name: String, #[validate(email)] pub email: String, #[validate(length(min = 6))] pub password: String, pub meta: Json<Meta>, }
报错信息
error[E0277]: the trait bound `sqlx::types::Json<Meta>: InputType` is not satisfied --> src/dto.rs:13:40 | 13 | #[derive(Debug, Deserialize, Validate, InputObject)] | ^^^^^^^^^^^ the trait `InputType` is not implemented for `sqlx::types::Json<Meta>` | = help: the following other types implement trait `InputType`: Arc<T> Arc<[T]> Arc<str> BTreeMap<K, V> BTreeSet<T> Box<T> Box<[T]> Box<str> and 49 others = note: this error originates in the derive macro `InputObject` (in Nightly builds, run with -Z macro-backtrace for more info)
解决方案
方案一:直接使用Meta类型替代sqlx::Json
因为已经为Meta实现了Scalar,可以修改RegisterInput的字段类型为Meta,在业务逻辑中再包装成sqlx::Json<Meta>:
修改后的RegisterInput:
#[derive(Debug, Deserialize, Validate, InputObject)] pub struct RegisterInput { #[validate(length(min = 4, max = 10))] pub name: String, #[validate(email)] pub email: String, #[validate(length(min = 6))] pub password: String, pub meta: Meta, // 替换为Meta类型 }
处理注册逻辑时转换类型:
async fn register(&self, input: RegisterInput) -> Result<User, Error> { // 将Meta包装成sqlx::Json类型 let sqlx_meta = Json(input.meta); // 执行数据库插入等操作 // ... }
方案二:手动为sqlx::Json实现InputType trait
利用Meta已实现的Scalar能力,为sqlx::Json<Meta>实现InputType:
use async_graphql::{InputType, Value, InputValueResult}; use sqlx::types::Json; #[async_graphql::Scalar] impl InputType for Json<Meta> { fn type_name() -> &'static str { Meta::type_name() } fn create_type_info(registry: &mut async_graphql::registry::Registry) -> async_graphql::registry::MetaType { Meta::create_type_info(registry) } fn parse(value: Value) -> InputValueResult<Self> { Meta::parse(value).map(Json) } fn to_value(&self) -> Value { self.0.to_value() } }
实现后,RegisterInput中可以继续保留pub meta: Json<Meta>的定义。
原因说明
User结构体中meta字段被#[graphql(skip)]标记,不需要实现OutputType,因此不会触发类型检查;而RegisterInput作为输入结构体,其所有字段都必须实现InputType,但Async Graphql并未为sqlx::Json<T>默认实现该 trait,所以需要手动处理。
内容的提问来源于stack exchange,提问作者Saadettin Yasir AKEL
相关产品推荐
相关产品推荐

