如何在Rust SQLx中创建自定义的Postgres枚举类型?

4
我正在尝试在Postgres中创建一个自定义的枚举类型,并且已经成功完成了。我的迁移代码如下:
CREATE TYPE role AS ENUM ('admin', 'user');

ALTER TABLE users
ADD role role DEFAULT 'user';

然后我在Rust中创建了这样的枚举类型:
#[derive(Serialize, Deserialize, Debug, sqlx::Type)]
#[sqlx(type_name = "role", rename_all = "lowercase")] 
pub enum Role {
    ADMIN,
    USER
}

而且我也修改了用户模型:

#[derive(sqlx::FromRow, Debug)]
pub struct User {
    pub id: i32,
    pub email: String,
    pub username: String,
    pub password: String,
    pub role: Role,
    pub created_at: DateTime<Utc>,
    pub updated_at: DateTime<Utc>,
}

但是现在当我尝试像这样查询数据库时:
let user = match sqlx::query_as!(
    User,
    "SELECT * FROM users WHERE email = $1 AND password = $2",
    &email,
    &password,
)

我遇到了这个错误:不支持列#7(“角色”)的类型 我做错了什么?
我已经尝试过调整宏部分 #[sqlx(type_name = "role", rename_all = "lowercase")]
但似乎没有起到帮助作用。
这是来自cargo check的完整错误信息:
error: unsupported type role of column #7 ("role")
   --> src/routes/auth/mod.rs:140:20
    |
140 |           let user = match sqlx::query_as!(
    |  __________________________^
141 | |             User,
142 | |             "SELECT * FROM users WHERE email = $1 AND password = $2",
143 | |             &payload.email,
144 | |             &hash,
145 | |         )
    | |_________^
    |
    = note: this error originates in the macro `$crate::sqlx_macros::expand_query` which comes from the expansion of the macro `sqlx::query_as` (in Nightly builds, run with -Z macro-backtrace for more info)

error: could not compile `rust-api-example` (bin "rust-api-example") due to previous error

运行时错误还是编译时错误?如果是编译时错误,cargo check 的完整错误信息是什么? - undefined
我已经使用完整错误信息更新了帖子。 - undefined
3个回答

1

我目前的情况与你非常相似,你的问题实际上帮助解决了我的问题。在我的情况下,将 #[sqlx(type_name = "user_role")] 添加到我的枚举类型中修复了我的问题。我将发布所有现在可正常工作的相关代码。希望这也能帮助解决你的问题。

我认为你的问题与使用 query_as 宏有关。该宏在自动映射自定义类型时存在问题,因此当你使用 SELECT * 时,它不理解如何映射结果。我不得不在我的 SQL 查询中手动指定类型,例如 user_role AS "user_role!: UserRole。我对 PostgreSQL 还不太熟悉,所以除了使用 AS 子句修复问题外,不太清楚更多信息。

以下帖子提供了更详细的信息:
https://github.com/launchbadge/sqlx/issues/235
https://users.rust-lang.org/t/sqlx-postgres-how-to-insert-a-enum-value/53044/2

这是我的 SQL 表/类型:

-- Create the enumeration type
CREATE TYPE user_role AS ENUM ('admin', 'user');

-- Create the roles table
CREATE TABLE
    roles (
        id SERIAL PRIMARY KEY,
        name user_role NOT NULL,
        created_at TIMESTAMP NOT NULL DEFAULT NOW ()
    );

-- Create the users table
CREATE TABLE
    users (
        id SERIAL PRIMARY KEY,
        username TEXT NOT NULL UNIQUE,
        password_hash TEXT NOT NULL,
        email TEXT NOT NULL UNIQUE,
        user_role user_role NOT NULL,
        created_at TIMESTAMP
        WITH
            TIME ZONE DEFAULT NOW (),
        updated_at TIMESTAMP
        WITH
            TIME ZONE DEFAULT NOW () 
    );

这是我的模型

#[derive(Clone, Debug, PartialEq, PartialOrd, sqlx::Type, Deserialize, Serialize)]
#[sqlx(type_name = "user_role", rename_all = "lowercase")]
pub enum UserRole {
    Admin,
    User,
}

#[derive(Debug, sqlx::FromRow, Deserialize, Serialize)]
#[allow(non_snake_case)]
pub struct UserModel {
    pub id: i32,
    pub username: String,
    pub password_hash: String,
    pub email: String, 
    pub user_role: UserRole,
    #[serde(rename = "createdAt")]
    pub created_at: Option<chrono::DateTime<chrono::Utc>>,
    #[serde(rename = "updatedAt")]
    pub updated_at: Option<chrono::DateTime<chrono::Utc>>,
}

这是我的插入函数:

let query_result = sqlx::query_as!(
        UserModel,
        r#"INSERT INTO users (username,password_hash,email,user_role) VALUES ($1, $2, $3, $4) RETURNING id,username,password_hash,email,user_role AS "user_role!: UserRole", created_at, updated_at"#,
        body.username.to_string(),
        body.password.to_string(),
        body.email.to_string(),
        UserRole::User as UserRole
    )
    .fetch_one(&data.db)
    .await;

0

0
我最终是这样修复的:
let user = sqlx::query_as!(
    model::User,
    "SELECT
    id,
    email,
    username,
    password,
    role AS \"role: model::Role\",
    created_at,
    updated_at
    FROM users WHERE id = $1",
    user_id
)
.fetch_one(&pool)
.await
.unwrap();

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