I feel like this is a pretty common thing to want to do, but I've spent a few hours wrangling with bounds and haven't been able to get anything to work.
pub fn search<T, C>(
table: T,
col: C,
query: String,
) -> T::Output
where
T: FilterDsl<Like<C, Bound<VarChar, String>>>,
C: Expression<SqlType = VarChar> + TextExpressionMethods,
{
let query = format!("%{query}%");
table.filter(col.like(query))
}
Essentially, I want to be able to search a given column of a given table for some string, in a generic way.
The code above works, but only generates the query. If I want to execute it, I need to call .load(conn)
on it. So I rewrote it to look like this:
pub fn search<T, C, M>( // extra type param for "model" type
table: T,
col: C,
query: String,
conn: SqliteConnection,
) -> Result<Vec<M>, diesel::result::Error>
where
T: FilterDsl<Like<C, Bound<VarChar, String>>>,
C: Expression<SqlType = VarChar> + TextExpressionMethods,
T::Output: LoadQuery<SqliteConnection, M>,
{
let query = format!("%{query}%");
table.filter(col.like(query)).load(&conn)
}
This causes an overflow error:
error[E0275]: overflow evaluating the requirement `<T as FilterDsl<Like<C, diesel::expression::bound::Bound<diesel::sql_types::Text, std::string::String>>>>::Output == _`
--> vit-servicing-station-lib/src/db/queries/search/generic.rs:32:1
|
32 | / pub fn search<T, C, M>(
33 | | table: T,
34 | | col: C,
35 | | query: String,
... |
40 | | C: Expression<SqlType = VarChar> + TextExpressionMethods,
41 | | T::Output: LoadQuery<SqliteConnection, M>,
| |______________________________________________^
When I read the constraint T::Output: LoadQuery<SqliteConnection, M>
, I think: "whatever the return type of table.filter(...)
is, that type should implement LoadQuery<_, _>
, which is the trait that .load()
comes from, so it should work".
But this overflow seems to indicate that there's a cycle somewhere (setting #![recursion_limit = "1000000"]
doesn't help), but I'm not sure where. I've also tried specifying <T as FilterDsl<_>>::Output
in the bound for T
, like:
T: FilterDsl<Like<C, Bound<VarChar, String>>, Output = ...>
in an attempt to break the cycle, but the error persists.
Can anyone spot what I'm doing wrong? I have a feeling I'm just missing one trait bound that will make this go away, but I can't for the life of me see it.
Thanks