launchbadge / sqlx

🧰 The Rust SQL Toolkit. An async, pure Rust SQL crate featuring compile-time checked queries without a DSL. Supports PostgreSQL, MySQL, and SQLite.
Apache License 2.0
13.32k stars 1.27k forks source link

Connection reference in a Trait #855

Open benjamingb opened 3 years ago

benjamingb commented 3 years ago

Is it possible to pass the reference of a connection in a trait?

use async_trait::async_trait;
#[async_trait]
pub trait ITodoRepo<P> {
    async fn list(pool: P);
}
#[derive(FromRow, Debug)]
pub struct TodoSchema {
    pub id: i32,
    pub body: Option<String>,
    pub complete: Option<String>,
}

pub struct TodoRepo;
#[async_trait]
impl<P> ITodoRepo<P> for TodoRepo {
    async fn list(pool: &P) -> Result<Vec<TodoType>> {
        let rowset = sqlx::query_as!(TodoSchema, r#"SELECT * FROM todo"#)
            .fetch_all(pool)
            .await?
            .iter()
            .map(|row| hydrate(row))
            .collect();

        Ok(rowset)
    }
}

fn hydrate(row: &TodoSchema) -> TodoType {
    TodoType {
        id: row.id,
        body: row.body.to_owned().unwrap_or("".to_owned()),
        complete: row.complete.to_owned().unwrap_or("".to_owned()),
    }
}

I am trying to do this but I get an error

  --> src/todo.rs:19:24
   |
19 |             .fetch_all(pool)
   |                        ^^^^ the trait `sqlx::Executor<'_>` is not implemented for `&P`

This is how I invoke the list method

 async fn todos(&self, ctx: &Context<'_>) -> FieldResult<Vec<TodoType>> {
        let pool = ctx.data::<PgPool>()?;
        let items = TodoRepo::list(pool).await?;
        Ok(items)
    }
Freyskeyd commented 3 years ago

Hello!

Did you try to pass something like that?

pub async fn stream_info(
    conn: impl sqlx::Executor<'_, Database = sqlx::Postgres>,
    stream_uuid: &str,
) -> Result<Stream, sqlx::Error> {}
benjamingb commented 3 years ago

Hi @Freyskeyd

I used it this way but it doesn't work either, the goal is for the trait to be generic

pub struct TodoRepo;
#[async_trait]
impl<P: sqlx::Executor<'_, Database = sqlx::Postgres>> ITodoRepo<P> for TodoRepo {
    async fn list(pool: &P) -> Result<Vec<TodoType>> {
        let rowset = sqlx::query_as!(TodoSchema, r#"SELECT * FROM todo"#)
            .fetch_all(pool)
            .await?
            .iter()
            .map(|row| hydrate(row))
            .collect();

        Ok(rowset)
    }
}
|
| impl<'a, P: sqlx::Executor<'_, Database = sqlx::Postgres>> ITodoRepo<'a, P> for TodoRepo {
|  
|
|             .fetch_all(pool)
|                        ^^^^ the trait `sqlx::Executor<'_>` is not implemented for `&P`
Freyskeyd commented 3 years ago

Did you try to remove the & ?, you can still use a reference.

See:

Method pass a mutable ref: https://github.com/Freyskeyd/chekov/blob/master/event_store/src/storage/postgres.rs#L89

The read_stream is here: https://github.com/Freyskeyd/chekov/blob/master/event_store/src/storage/postgres/sql.rs#L11

benjamingb commented 3 years ago

when I use a direct reference if it works async fn list(pool: &PgPool) -> Result<Vec<TodoType>> https://github.com/benjamingb/rust/todo.rs#L13

I am trying to implement it with a trait so that it is generic and can be used in other crates

Here is a reference to the project https://github.com/benjamingb/rust-gql/tree/develop/src

Freyskeyd commented 3 years ago

Mmh I didnt' have time to check on a running exemple but I think something like that would work no?

Or am I missing something ?

pub struct TodoRepo;

#[async_trait]
impl<P: sqlx::Database>> ITodoRepo<P> for TodoRepo {
    async fn list(pool: impl sqlx::Executor<'_, Database = P>) -> Result<Vec<TodoType>> {
        let rowset = sqlx::query_as!(TodoSchema, r#"SELECT * FROM todo"#)
            .fetch_all(pool)
            .await?
            .iter()
            .map(|row| hydrate(row))
            .collect();

        Ok(rowset)
    }
}
benjamingb commented 3 years ago

Thank you very much for your help but it still doesn't work :(

sylvain101010 commented 3 years ago

Hi @benjamingb Did you find a solution? I'm facing the same problem

benjamingb commented 3 years ago

Hi @skerkour, not yet, I'm looking for other alternatives