The trait bound `Uuid: Type<Postgres>` is not satisfied

Hey everyone, so I'm trying to use the UUID data type for my Announcement struct

use actix_web::{
    get, post,
    web::{Data, Json, Path},
    Responder, HttpResponse
};
use serde::{Deserialize, Serialize} ;
use sqlx::{
    self, postgres::PgRow, Error, FromRow, Postgres
};
use uuid::Uuid;
use crate::AppState;
use sqlx::Row;

#[derive(Serialize)]
struct Announcement {
    announcement_uid: String,
    info: String,
    date: String,
    club_uid: Uuid
}

The problem is that I want to bind my club_uid field to a sqlx query so I tried manually implementing the FromRow trait for the Announcement struct. Unfortunately, I then got the error: the trait bound Uuid: Type<Postgres> is not satisfied

impl<'r> FromRow<'r, PgRow> for Announcement
where
    Uuid: ::sqlx::decode::Decode<'r, Postgres>,
    Uuid: ::sqlx::types::Type<Postgres>,
{
    fn from_row(row: &'r PgRow) -> Result<Self, Error> {
        let announcement_uid: String = row.try_get("announcement_uid")?;
        let info: String = row.try_get("info")?;
        let date: String = row.try_get("date")?;
        let club_uid: Uuid = row.try_get("club_uid")?;

        Ok(Announcement { announcement_uid, info, date, club_uid })
    }
}

Not only that but when I try binding my club_uid to a sqlx query, I got the error: the trait bound Result<Uuid, uuid::Error>: Encode<'_, _> is not satisfied

#[post("/announcement")]
pub async fn create_announcement(state: Data<AppState>, body: Json<CreateAnnouncement>) -> impl Responder {
    match sqlx::query_as::<_, Announcement>(
        "INSERT INTO announcement (announcement_uid, info, date, club_uid) VALUES (uuid_generate_v4(), $1, $2, $3) RETURNING announcement_uid, info, date"
    )
        .bind(body.info.to_string())
        .bind(body.date.to_string())
        .bind(Uuid::parse_str(body.club_uid.as_str()))
        .fetch_one(&state.db)
        .await
    {
        Ok(announcement) => HttpResponse::Ok().json(announcement),
        Err(e) => {
            println!("{}", e);
            HttpResponse::InternalServerError().json("Failed to create club announcement")
        }
    }
}

I'm really new to Rust so any assistance would be helpful. Thanks in advance!

Edit: Here's my cargo build

error[E0599]: no method named `as_str` found for struct `Uuid` in the current scope
  --> src\services.rs:85:45
   |
85 |         .bind(Uuid::parse_str(body.club_uid.as_str()).expect("foo"))
   |                                             ^^^^^^ method not found in `Uuid`

For more information about this error, try `rustc --explain E0599`.

Do you have the uuid feature of sqlx activated?

I just added the uuid features and it worked!
The only persisting error is in .bind(Uuid::parse_str(body.club_uid.as_str())) because I'm still getting the error: the trait bound Result<Uuid, uuid::Error>: Encode<'_, _> is not satisfied

Uuid::parse_str() does not return a Uuid. Instead it return Result<Uuid, Error>. so you need to handle the result first.

Hi @romeil , welcome!

The error you mentioned above may be enough for someone familiar with these crates to figure out the problem, but in general please post the full error you get from cargo build in the terminal. This has more context and hints.

Hi @jumpnbrownweasel, I just shared it

1 Like

It seems that .as_str() isn't a method in Uuid. Is there another way to get around this?

Uuid implements the Display trait, so you can do this:

format!("{}", uuid)

Or if the output format is not to your liking, try the Debug format:

format!("{:?}", uuid)
1 Like

This is a little bit suspicious because it looks like you're converting a Uuid to a String and then back to a Uuid, is that right? If so, it is probably more efficient and cleaner to clone the Uuid,

body.club_uid.clone()

since the Clone trait is also implemented by Uuid.


As @quinedot just pointed out, Copy is also implemented so you can remove the call to clone() above.

1 Like

(So is Copy.)

1 Like

I forgot to mention the use of the CreateAnnouncement struct within the provided JSON body. The club_uid field was previously of type UUID but I've now changed it to a String.

Here is the struct now:

pub struct CreateAnnouncement {
    pub info: String,
    pub date: String,
    pub club_uid: String,
}

Moreover, so as to get a better understanding of the whole picture, here's my new function:

#[post("/announcement")]
pub async fn create_announcement(state: Data<AppState>, body: Json<CreateAnnouncement>) -> impl Responder {
    match sqlx::query_as::<_, Announcement>(
        "INSERT INTO announcement (announcement_uid, info, date, club_uid) VALUES ($1, $2, $3, $4) RETURNING CAST(announcement_uid AS TEXT), info, date, club_uid"
    )
        .bind(Uuid::new_v4())
        .bind(body.info.to_string())
        .bind(body.date.to_string())
        .bind(Uuid::parse_str(body.club_uid.as_str()).expect("foo"))
        .fetch_one(&state.db)
        .await
    {
        Ok(announcement) => HttpResponse::Ok().json(announcement),
        Err(_) => HttpResponse::InternalServerError().json("Failed to create club announcement"),
    }
}

Apologies for any confusion I've caused

1 Like

This topic was automatically closed 90 days after the last reply. We invite you to open a new topic if you have further questions or comments.