Skip to content

[Postgres] RowNotFound when mapping enum to varchar column #237

@jamwaffles

Description

@jamwaffles

I'm trying to read/write enums to/from a varchar not null column in Postgres. This issue may also exhibit in other databases, but I haven't tested them. As far as I can see from the docs, creating an enum like the following should allow me to use it in a query:

#[derive(
    serde_derive::Deserialize, serde_derive::Serialize, sqlx::Type,
)]
#[sqlx(rename = "TEXT")]
pub enum UserType {
    #[sqlx(rename = "users_normal")]
    Normal,

    #[sqlx(rename = "users_admin")]
    Admin,
}

My insert statement looks like this:

let user: User = sqlx::query_as(
        "insert into users
            (id, name, user_type)
        values
            ($1, $2, $3)
        on conflict (id) do update set
            name = excluded.name,
            user_type = excluded.user_type
        returning *
        ",
    )
    .bind(user_id)
    .bind("Bobby Beans".to_string())
    .bind(UserType::Normal)
    .fetch_one(&postgres)
    .await
    .unwrap();

The record is never created in the database, and the insert panics with this message:

thread 'main' panicked at 'called `Result::unwrap()` on an `Err` value: RowNotFound'

Removing the UserType enum from the insert lets it work as normal, and inserts the record into the database.

I've tried changing #[sqlx(rename = "TEXT")] to #[sqlx(rename = "varchar not null")] to mirror the column type to no avail (see case below).

Is this a bug, or am I not following the docs properly? I found some stuff in CHANGELOG.md about this but it's not very clear.


This is the reduced (as much as possible) test case.

Note that removing all serde stuff doesn't fix the issue, so it's not serde messing with things.

use sqlx::{postgres::PgQueryAs, PgPool};
use uuid::Uuid;

#[derive(
    serde_derive::Deserialize, serde_derive::Serialize, Debug, Copy, Clone, PartialEq, sqlx::Type,
)]
#[sqlx(rename = "TEXT")]
pub enum UserType {
    #[serde(rename = "users_normal")]
    #[sqlx(rename = "users_normal")]
    Normal,

    #[serde(rename = "users_admin")]
    #[sqlx(rename = "users_admin")]
    Admin,
}

#[derive(
    serde_derive::Deserialize, serde_derive::Serialize, Debug, Clone, PartialEq, sqlx::FromRow,
)]
pub struct User {
    id: Uuid,
    name: String,
    user_type: UserType,
}

#[async_std::test]
async fn enum_text_type() {
    let postgres = PgPool::new(&std::env::var("DATABASE_URL").unwrap())
        .await
        .expect("Error creating postgres pool");

    sqlx::query(
        r#"
            create table if not exists users (
                id uuid primary key,
                name varchar not null,
                user_type varchar not null
            );
        "#,
    )
    .execute(&postgres)
    .await
    .expect("Failed to create users table");

    let user_id = Uuid::new_v4();

    let user: User = sqlx::query_as(
        "insert into users
            (id, name, user_type)
        values
            ($1, $2, $3)
        on conflict (id) do update set
            name = excluded.name,
            user_type = excluded.user_type
        returning *
        ",
    )
    .bind(user_id)
    .bind("Bobby Beans".to_string())
    .bind(UserType::Normal)
    .fetch_one(&postgres)
    .await
    .unwrap();

    assert_eq!(
        user,
        User {
            id: user_id,
            name: "Bobby Beans".to_string(),
            user_type: UserType::Normal
        }
    )
}

Cc @Istar-Eldritch who's been helping me fight this issue.

Metadata

Metadata

Assignees

No one assigned

    Labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions