如何在 Rust 的 sqlx 模型中将枚举的 Vec 定义为字段

6
我正在尝试将Postgres中的数组字段加载到Rust结构体中,如下所示。
use sqlx::{Pool, PgConnection, PgPool, FromRow};
use sqlx::postgres::PgQueryAs;

#[derive(Copy, Clone, sqlx::Type)]
#[sqlx(rename = "VARCHAR")]
#[sqlx(rename_all = "snake_case")]
enum Coupon {
    ChristmasSaleCoupon,
    NewYearSaleCoupon,
}

#[derive(FromRow, Clone)]
struct UserCouponMap {
    pub id: i64,
    pub user_id: i64,
    pub coupons: Vec<Coupon>,
}

impl UserCouponMap {
    pub async fn get_for_userid(db_pool: Pool<PgConnection>, user_id: i64) -> Vec<UserCouponMap> {
        let user_coupon_map: Vec<UserCouponMap> = sqlx::query_as("SELECT * FROM user_coupon_map WHERE user_id = $1")
            .bind(user_id)
            .fetch_all(db_pool)
            .await
            .expect("failed to fetch user coupon map");
        user_coupon_map
    }
}


#[tokio::main]
async fn fetch_coupons_for_user_id(user_id: i64) {
    let pool = PgPool::new("postgresql://asnim@dbhost:5732").await.expect("expected unwrap to succeed");
    let user_coupon_map = UserCouponMap::get_for_userid(pool, user_id).await;
}

fn main() {
    fetch_coupons_for_user_id(20);
}

根据文档,我已经为Coupon实现了sqlx::Type
然而,编译器提示存在某些未满足的特性。
   Compiling playground v0.1.0 (/Users/asnimansari/CLionProjects/playground)
error[E0277]: the trait bound `Vec<Coupon>: Type<Postgres>` is not satisfied
  --> src/main.rs:23:14
   |
23 |             .fetch_all(db_pool)
   |              ^^^^^^^^^ the trait `Type<Postgres>` is not implemented for `Vec<Coupon>`
   |
   = help: the following implementations were found:
             <Vec<&[u8]> as Type<Postgres>>
             <Vec<&str> as Type<Postgres>>
             <Vec<(T1, T2)> as Type<Postgres>>
             <Vec<(T1, T2, T3)> as Type<Postgres>>
           and 29 others
   = note: required because of the requirements on the impl of `for<'c> FromRow<'c, PgRow<'c>>` for `UserCouponMap`

error[E0277]: the trait bound `[Coupon]: Type<Postgres>` is not satisfied
  --> src/main.rs:23:14
   |
23 |             .fetch_all(db_pool)
   |              ^^^^^^^^^ the trait `Type<Postgres>` is not implemented for `[Coupon]`
   |
   = help: the following implementations were found:
             <[&[u8]] as Type<Postgres>>
             <[&str] as Type<Postgres>>
             <[(T1, T2)] as Type<Postgres>>
             <[(T1, T2, T3)] as Type<Postgres>>
           and 29 others
   = note: required because of the requirements on the impl of `sqlx::decode::Decode<'_, Postgres>` for `Vec<Coupon>`
   = note: required because of the requirements on the impl of `for<'c> FromRow<'c, PgRow<'c>>` for `UserCouponMap`

error: aborting due to 3 previous errors

For more information about this error, try `rustc --explain E0277`.
error: could not compile `playground`

To learn more, run the command again with --verbose.


我在这里缺少什么?

我的Cargo文件有以下依赖项

sqlx = { version = "0.3.5", default-features = false, features = ["runtime-tokio", "macros", "postgres", "all-type"] }
tokio = { version = "0.2.21", features = ["full"] }

你能找到解决方案吗? - martinomburajr
@martinomburajr 不是的 - Asnim P Ansari
1个回答

2

它应该以以下一种方式工作:使用明确的列列表并在查询中声明Rust类型。对于 OP 的情况:

let user_coupon_map: Vec<UserCouponMap> = sqlx::query_as!(
    r#"SELECT id, user_id, coupons as "coupons: Vec<Coupon>"
    FROM user_coupon_map 
    WHERE user_id = $1"#
)...

它可能不能满足您的所有需求。如果您使用像sea_query这样的查询构建器,那么它就不会起作用。


错误发生在编译时,因此在这个例子中,调整查询(在编译时没有解析)是无济于事的。 - Dave Rolsky
抱歉,你是正确的。我已经编辑了宏解决方案的帖子。这只能使用query_as!()宏而不是函数query_as()。生成的宏代码应该采用Rust类型提示“coupons: Vec<Coupon>”,并使用正确的类型。 - im__
我不确定这会不会起作用。你测试过了吗?我有一些非常相似的代码,我得到了这个错误:^Trait \Type<Postgres>` 没有实现 for `Vec<NameType>`` - Dave Rolsky
1
我在项目中有这方面的实例,并且对于以下情况,对我来说都运行良好:将pg array []转换为Vec<CustomType>,如操作者的情况,将JSONB转换为Json<RustType>,并将NOT NULL字段强制转换为rust Option<Type>而不仅仅是 Type。已在sqlx 0.5.9中进行了测试。 - im__

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接