Implement a trait that changes a type from sqlx to an enum I created

53 Views Asked by At

I've got this code that matches a type coming from an unknown sqlx query. In the example, it's PgRow and I want to transform it into an enum MyDynamicValue depending on the type_info. I could implement it for every type defined by every databases and add an entry in the match. I think that you can see that it's a lot repetitive.

fn get_row_value(row: &PgRow, col_index: usize) -> Result<Option<MyDynamicValue>> {
    let value_ref = row
        .try_get_raw(col_index)
        .map_err(|err| Error::RunQueryError)?;
    Ok(match value_ref.type_info().name() {
        "VARCHAR" => row
            .try_get::<Option<String>, usize>(col_index)
            .map_err(|err| Error::RunQueryError)?
            .map(|value| MyDynamicValue::String(value)),
        "INT4" => row
            .try_get::<Option<i32>, usize>(col_index)
            .map_err(|err| Error::RunQueryError)?
            .map(|value| MyDynamicValue::Integer(value)),
        "BYTEA" => row
            .try_get::<Option<&[u8]>, usize>(col_index)
            .map_err(|err| Error::RunQueryError)?
            .map(|value| MyDynamicValue::Bytea(value.to_owned())),
            // ...
        name => panic!("UNHANDLED DATABASE TYPE: {name}"),
    })
}

#[derive(PartialEq, Debug, Clone)]
pub enum MyDynamicValue {
    String(String),
    Integer(i32),
    Bytea(Vec<u8>),
}

The parts that I want to refactor is:

        "VARCHAR" => row
            .try_get::<Option<String>, usize>(col_index)
            .map_err(|err| Error::RunQueryError)?
            .map(|value| MyDynamicValue::String(value)),

And I would like to only write:

row.try_get(col_index).into()

The problem is that I match on type_info.name() to know the type of the output.

Anyway, I'm not sure about good pratices and if someone can lighten the path, I'll gladly follow.

I tried a few things always lead to me realizing I was in over my head.

I tried implementing From<dyn Decode<'a, T, DB>>: compiler was not happy.

How can I make this code less repetitive?

Bonus question: How can I even do it for any database type?

0

There are 0 best solutions below