rwf2 / Rocket

A web framework for Rust.
https://rocket.rs
Other
24.5k stars 1.57k forks source link

UUID type conversion error #1169

Closed treyhakanson closed 4 years ago

treyhakanson commented 4 years ago

Rocket version: 0.4.2 OS: macOS Mojave 10.14.5

When using rocket with the postgres, and uuid features, I get the following error on trying to pull a uuid out of the DB:

type conversion error: cannot convert to or from a Postgres value of type `uuid`

Here is a link to a minimal example; run the SQL commands to setup the database, and create an entry, and then make the following request:

curl http://localhost:8000/foo/<uuid>

The request will return a 404, and you'll see the error mentioned above in the logs.

I'm fairly new to Rust, but my suspicion is that there is that there's a version mismatch between these libraries. The uuid feature of rust-postgres appears to only work with uuid version 0.5, but rocket_contrib is using 0.7.4. Also note that I tried falling back to the uuid-ossp extension since I was originally using pgcrypto, but that did not help.

jebrosen commented 4 years ago

I don't see any use of uuid in that example, so I doubt that is the problem (yet). You are correct that the uuid versions do not match, and if/when you do start using Uuid you will need to convert between the two versions via strings or just strings entirely in one place or another.

I believe the error occurs because you tried to convert or compare a rust String to or from a postgres UUID either in the WHERE clause or in the return type you requested. String doesn't look compatible with UUID according to the lists for ToSql or FromSql

treyhakanson commented 4 years ago

Awesome, you were correct about that; thanks for the help! Feels a little gnarly to have to do something like this every time a uuid is used thought:

use rocket_contrib::uuid::Uuid as RocketUuid;
use uuid::Uuid;

// ...

#[get("/foo/<id>")]
fn foo(conn: DBConn, id: RocketUuid) -> Option<String> {
    let pg_uuid = Uuid::parse_str(&id.to_string()).unwrap();
    match conn.query(
        "
        SELECT id
        FROM foo
        WHERE id = $1;
    ",
        &[&pg_uuid],
    ) {
        Ok(result) => Some(result.get(0).get::<&str, Uuid>(&"id").to_string()),
        Err(e) => {
            error!(target: "foo", "Error fetching foo: {}", e.to_string());
            None
        }
    }
}

Is there a better way? Luckily the rc and alpha versions of rust-postgres appear to be using uuid 0.7 so this hopefully won't be a problem for much longer

jebrosen commented 4 years ago

Converting through Bytes/UuidBytes (both type aliases for [u8; 16]) instead of String should be more efficient. You could also implement traits to provide convenient shorthand like .to_uuid5() or .to_uuid7(), but the version conflict is unfortunately pretty unavoidable for now.

treyhakanson commented 4 years ago

Great, your trait idea should be enough for me to get by for now; thanks again for the help, I really appreciate it!