You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.08 11:15:59