sqlx::query! Macro with uuid::Uuid Fails to Compile in Rust

291 Views Asked by At

I'm attempting to insert data into a PostgreSQL database using sqlx::query! macro in Rust. However, I'm encountering a compilation error related to the uuid::Uuid type not satisfying the Encode trait.

Error Message:

the trait bound uuid::Uuid: Encode<'_, Postgres> is not satisfied

Code Snippet:

use actix_web::{web, HttpResponse};
use sqlx::PgPool;
use uuid::Uuid;
use chrono::Utc;

pub async fn subscribe(form: web::Form<FormData>, connection: web::Data<PgPool>) -> HttpResponse {
    sqlx::query!(
        r#"
        INSERT INTO subscriptions (id, email, name, subscribed_at)
        VALUES ($1, $2, $3, $4)
        "#,
        Uuid::new_v4(),
        form.email,
        form.name,
        Utc::now()
    )
    .execute(connection.get_ref())
    .await;
    HttpResponse::Ok().finish()
}

Cargo.toml Dependencies:

[dependencies]
actix-web = "4.4.0"
sqlx = { version = "0.7", default-features = false, features = ["runtime-tokio-rustls", "macros", "postgres", "uuid", "chrono"] }
uuid = { version = "0.8.1", features = ["v4", "serde"] }
chrono = "0.4.15"

Attempts to Solve:

  • I have ensured that the uuid feature is enabled in sqlx.
  • I tried different versions of uuid to check for compatibility.
  • I ran cargo clean and cargo build after changes to Cargo.toml.

What could be causing this trait bound issue and how can I resolve it? Is there a version mismatch, or am I missing a necessary feature activation?

Update

I update the codes with this codes but still show me error :

use actix_web::{web, HttpResponse};
use chrono::Utc;
use sqlx::types::Uuid;
use sqlx::PgPool;

#[derive(serde::Deserialize)]
pub struct FormData {
    email: String,
    name: String,
}

pub async fn subscribe(form: web::Form<FormData>, connection: web::Data<PgPool>) -> HttpResponse {
    let my_uuid = Uuid::parse_str("a1a2a3a4b1b2c1c2d1d2d3d4d5d6d7d8")?;
    
    sqlx::query!(
        r#"
    INSERT INTO subscriptions (id, email, name, subscribed_at)
    VALUES ($1, $2, $3, $4)
    "#,
        my_uuid,
        form.email,
        form.name,
        Utc::now()
    )
    // We use `get_ref` to get an immutable reference to the `PgConnection`
    // wrapped by `web::Data`.
    .execute(connection.get_ref())
    .await;
    HttpResponse::Ok().finish()
}

it shows me this error :

let my_uuid = Uuid::parse_str("a1a2a3a4b1b2c1c2d1d2d3d4d5d6d7d8")?;

the ? operator can only be used in an async function that returns Result or Option (or another type that implements FromResidual) the trait FromResidual<Result<Infallible, sqlx::types::uuid::Error>> is not implemented for HttpResponse

2

There are 2 best solutions below

2
On BEST ANSWER

sqlx doesn't know how to serialize a Uuid but it knows how to serialize a String, so you can convert the Uuid to String using the to_string method on Uuid:

pub async fn subscribe(form: web::Form<FormData>, connection: web::Data<PgPool>) -> HttpResponse {
    sqlx::query!(
        r#"
    INSERT INTO subscriptions (id, email, name, subscribed_at)
    VALUES ($1, $2, $3, $4)
    "#,
        // Here we use the `to_string` method on `Uuid`
        Uuid::new_v4().to_string(),
        form.email,
        form.name,
        Utc::now()
    )
    .execute(connection.get_ref())
    .await;

    HttpResponse::Ok().finish()
}

In the updated version of your code, you are parsing a String into an Uuid which may fail, that's why the Uuid::parse method returns a Result, you can either unwrap it (if you are sure that it's a valid Uuid) or handle the error like so:

pub async fn subscribe(form: web::Form<FormData>, connection: web::Data<PgPool>) -> HttpResponse {
    // unwrap it
    let my_uuid = Uuid::parse_str("a1a2a3a4b1b2c1c2d1d2d3d4d5d6d7d8").unwrap();

    // or, handle the error
    let my_uuid = match Uuid::parse_str("a1a2a3a4b1b2c1c2d1d2d3d4d5d6d7d8") {
        Ok(uuid) => uuid,
        Err(err) => {
            return HttpResponse::BadRequest().body("Invalid uuid");
        }
    };
    
    sqlx::query!(
        r#"
    INSERT INTO subscriptions (id, email, name, subscribed_at)
    VALUES ($1, $2, $3, $4)
    "#,
        // We have to convert `Uuid` to `String`
        my_uuid.to_string(),
        form.email,
        form.name,
        Utc::now()
    )
    .execute(connection.get_ref())
    .await;
    HttpResponse::Ok().finish()
}
0
On

I also tried to run the same code from Zero to Production by Luca Palmieri. It turns sqlx 0.5.x has a bug:

Uuid breaks with version 1 with SQLx

upgrading it from .5.X to the latest 0.7 in Cargo.toml fixed the problem in the original.