-
Hello, I am implementing a JSON:API Rust library. In order to resolve the relationships between the resources, I need to implement a resolver (a Here is my current implementation: pub trait ResourceModel<Resource>: Into<Resource> + From<Resource> + HasTable {
type Changeset;
}
pub fn select_by_ids<'query, Resource, Model>(&self, ids: Vec<String>) -> Result<Vec<Resource>>
where
Model: ResourceModel<Resource>,
// Required by PrimaryKey::eq_any()
<Model::Table as Table>::PrimaryKey: ExpressionMethods,
<<Model::Table as Table>::PrimaryKey as Expression>::SqlType: SqlType,
// Required to compare String and PrimaryKey
String: AsExpression<<<Model::Table as Table>::PrimaryKey as Expression>::SqlType>,
// Required by FilterDsl::filter()
Model::Table: FilterDsl<
EqAny<<Model::Table as Table>::PrimaryKey, Vec<String>>,
Output = <Model::Table as AsQuery>::Query,
>,
<Model::Table as AsQuery>::Query: LoadQuery<'query, Connection, Model>,
{
let conn = &mut self.connection().clone().get().unwrap();
FilterDsl::filter(Model::table(), Model::table().primary_key().eq_any(ids))
.load::<Model>(conn)
.map(|rows| rows.into_iter().map(Into::<Resource>::into).collect())
.map_err(|err| vec![err.to_jsonapi_error()])
} But it causes the following error at build:
The problem is But I cannot find how to set the proper type for Regards, |
Beta Was this translation helpful? Give feedback.
Replies: 1 comment 2 replies
-
I generally advice not to write such generic code (at least not for application code) as it involves these complex hard to write type bounds. That written: As you already noticed, each call of one of the pub fn select_by_ids<Resource, Model, Connection>(
conn: &mut Connection,
ids: Vec<String>,
) -> QueryResult<Vec<Resource>>
where
Model: ResourceModel<Resource>,
// Required by PrimaryKey::eq_any()
<Model::Table as Table>::PrimaryKey: ExpressionMethods,
<<Model::Table as Table>::PrimaryKey as Expression>::SqlType: SqlType,
// Required to compare String and PrimaryKey
String: AsExpression<<<Model::Table as Table>::PrimaryKey as Expression>::SqlType>,
// Required by FilterDsl::filter()
Model::Table: BoxedDsl<'static, Connection::Backend>,
for<'query> IntoBoxed<'static, Model::Table, Connection::Backend>: FilterDsl<
EqAny<<Model::Table as Table>::PrimaryKey, Vec<String>>,
Output = IntoBoxed<'static, Model::Table, Connection::Backend>,
> + LoadQuery<'query, Connection, Model>,
Connection: diesel::connection::LoadConnection,
{
Model::table()
.into_boxed()
.filter(Model::table().primary_key().eq_any(ids))
.load(conn)
.map(|rows| rows.into_iter().map(Into::<Resource>::into).collect())
} |
Beta Was this translation helpful? Give feedback.
I generally advice not to write such generic code (at least not for application code) as it involves these complex hard to write type bounds. That written: As you already noticed, each call of one of the
QueryDsl
methods changes the returned type. That's used by diesel to perform all these compile time checks. If you now write generic code you need to proof to the compiler that all these bounds hold, which is depending on the amount of methods you use a quite large task. You can make it a bit easier by boxing the query viaQueryDsl::into_boxed()
, as that "fixes" the query type to a (mostly) concrete type. By doing that I can modify your example to be something like that: