Rust Sqlx 处理 INSERT ON CONFLICT

Joh*_*rgo 3 rust actix-web rust-sqlx

我有一个查询将用户的数据插入数据库。它工作正常,但该users表在 上有一个唯一索引username,因此当尝试创建用户名已存在的行时,它会抛出错误:

pub async fn create(user: UserRequest, pool: &PgPool) -> anyhow::Result<User> {
   let new_user = sqlx::query_as!(
       User,
       r#"
       INSERT INTO users (first_name, username)
       VALUES ($1, $2)
       RETURNING id, first_name, username
       "#,
       &user.first_name,
       &user.username,
   )
   .fetch_one(&pool.clone())
   .await?;
    
   Ok(User {
       id: new_user.id,
       first_name: new_user.first_name,
       username: new_user.username,
   })
}
Run Code Online (Sandbox Code Playgroud)

&user是一个函数参数,定义为:

pub struct UserRequest {
    pub first_name: String,
    pub username: String,
}
Run Code Online (Sandbox Code Playgroud)

使用此函数的端点用于match检查它是否是Ok(user)或其他任何内容,并返回其响应:

pub async fn create_user(
    user: web::Json<UserRequest>,
    pool: Data<PgPool>,
) -> impl Responder {
    let new_user = User::create(user.into_inner(), pool.get_ref()).await;
    match new_user {
        Ok(user) => HttpResponse::Ok().json(user),
        _ => HttpResponse::BadRequest().body(ERROR_MESSAGE),
    }
}
Run Code Online (Sandbox Code Playgroud)

当由于尝试复制行而出现错误时,我该怎么做才能捕获这种情况?情况是,当发生这种情况时,我需要返回不同的 HTTP 状态。

sty*_*ane 6

您可以使用 检查错误代码get_code

match new_user {
    Ok(user) => HttpResponse::Ok().json(user),
    Err(err) if err.get_code() == "23505" {
    // returns unique constraint violation response.
    },
    _ => HttpResponse::BadRequest().body(ERROR_MESSAGE),
}
Run Code Online (Sandbox Code Playgroud)

为了让这项工作像@MichaelAnderson 在评论中指出的那样,

您需要将 create 的返回类型更改为Result<User, sqlx::postgres::PgDatabaseError>,或者您可以使用anyhow::Error::downcast或其相关函数返回到 aPgDatabaseError

  • 感谢你们抽出宝贵的时间,伙计们(我知道评论不是为了表达感激之情,但我是一个感恩的人:*) (3认同)
  • 要实现此功能,您需要将 `create` 的返回类型更改为 `Result&lt;User, sqlx::postgres::PgDatabaseError&gt;`。 (2认同)
  • 或者,您可以使用“anyhow::Error::downcast”或其相关函数返回到“PgDatabaseError”,而不是更改 create 的返回类型 (2认同)