kurtbuilds / ormlite

An ORM in Rust for developers that love SQL.
https://crates.io/crates/ormlite
MIT License
216 stars 11 forks source link

Cannot pass &str to get_one() #3

Closed heroin-moose closed 2 years ago

heroin-moose commented 2 years ago

The following example fails to compile:

use anyhow::Result;
use ormlite::Model;
use ormlite::model::*;
use sqlx::SqlitePool;
use sqlx::FromRow;

#[derive(Model, FromRow)]
struct Example {
    #[ormlite(primary_key)]
    name: String
}

async fn get(pool: &SqlitePool, name: impl AsRef<str>) -> Result<Example> {
    Example::get_one(name.as_ref(), pool).await.map_err(|e| e.into())
}

#[tokio::main]
async fn main() -> Result<()> {
    let pool = SqlitePool::connect("/tmp/database").await?;
    let example = get(&pool, "name");
    Ok(())
}

The error:

error[E0277]: the trait bound `for<'r> &str: Encode<'r, sqlx::Sqlite>` is not satisfied
  --> src/main.rs:14:37
   |
14 |     Example::get_one(name.as_ref(), pool).await.map_err(|e| e.into())
   |     ----------------                ^^^^ the trait `for<'r> Encode<'r, sqlx::Sqlite>` is not implemented for `&str`
   |     |
   |     required by a bound introduced by this call
   |
   = help: the following implementations were found:
             <&'q str as Encode<'q, sqlx::Any>>
             <&'q str as Encode<'q, sqlx::Sqlite>>
             <&str as Encode<'_, sqlx::Postgres>>
note: required by `get_one`
  --> /home/consus/.cargo/registry/src/github.com-1ecc6299db9ec823/ormlite-core-0.1.3/src/model.rs:77:5
   |
77 | /     fn get_one<'e, 'a, Arg, E>(id: Arg, db: E) -> BoxFuture<'e, Result<Self>>
78 | |     where
79 | |         'a: 'e,
80 | |         E: 'e + sqlx::Executor<'e, Database = DB>,
81 | |         Arg: 'a + Send + for<'r> sqlx::Encode<'r, DB> + sqlx::Type<DB>;
   | |_______________________________________________________________________^

For more information about this error, try `rustc --explain E0277`.
error: could not compile `ormlite-issue` due to previous error

However, changing name.as_ref() into name.as_ref().to_string() fixes it.

kurtbuilds commented 2 years ago

This may or may not be difficult to fix. I'll see if I was too strict with that bound and can reduce it to make this code work.

kurtbuilds commented 2 years ago

I cut 0.1.6 to fix this issue.

I pushed an update to https://github.com/kurtbuilds/ormlite-issue that demos the fix.

Unfortunately, AsRef is only one of the necessary bounds. The full signature needs to be something like:

async fn get<'a>(pool: &SqlitePool, name: impl AsRef<str> + sqlx::Encode<'a, sqlx::Sqlite> + Send + Sync + sqlx::Type<sqlx::Sqlite> + 'a) -> Result<Example>

You can of course name this collection of traits if you find yourself reusing it frequently. I'd like to find a better long term solution, whether thats exporting such trait groupings from ormlite, or finding a way to reduce the number of traits required altogether.