0

I am trying to order diesel queries dynamically, something like this question. QueryOrdering::order_query works fine, but when I tried to create the DynOrderDsl trait, so that I can build the queries by chaining functions like in the example fn I cannot get the code to compile.

I think the trait bounds should be fine, since those are all copy pasted from QueryOrdering::order_query which works.

#[macro_use]
extern crate diesel;

use diesel::backend::Backend;
use diesel::dsl::{Asc, Desc};
use diesel::helper_types::IntoBoxed;
use diesel::query_dsl::methods::{BoxedDsl, OrderDsl};
use diesel::{table, ExpressionMethods, QueryDsl};

table! {
    posts (id) {
        id -> Nullable<Integer>,
    }
}

enum QueryOrdering {
    Ascending,
    Descending,
}

impl QueryOrdering {
    fn order_query<'a, Expr, Q, DB>(&self, query: Q, expr: Expr) -> IntoBoxed<'a, Q, DB>
    where
        Expr: ExpressionMethods,
        Q: QueryDsl + BoxedDsl<'a, DB>,
        DB: Backend,
        IntoBoxed<'a, Q, DB>: OrderDsl<Asc<Expr>, Output = IntoBoxed<'a, Q, DB>>
            + OrderDsl<Desc<Expr>, Output = IntoBoxed<'a, Q, DB>>,
    {
        match self {
            Self::Ascending => query.into_boxed().order(expr.asc()),
            Self::Descending => query.into_boxed().order(expr.desc()),
        }
    }
}

pub trait DynOrderDsl<'a, DB, Expr>
where
    Expr: ExpressionMethods,
    Self: QueryDsl + BoxedDsl<'a, DB>,
    DB: Backend,
    IntoBoxed<'a, Self, DB>: OrderDsl<Asc<Expr>, Output = IntoBoxed<'a, Self, DB>>
        + OrderDsl<Desc<Expr>, Output = IntoBoxed<'a, Self, DB>>,
{
    fn dyn_order(self, order: QueryOrdering, expr: Expr) -> IntoBoxed<'a, Self, DB>;
}

impl<'a, Expr, DB, Q> DynOrderDsl<'a, Expr, DB> for Q
where
    Expr: ExpressionMethods,
    Q: QueryDsl + BoxedDsl<'a, DB>,
    DB: Backend,
    IntoBoxed<'a, Q, DB>: OrderDsl<Asc<Expr>, Output = IntoBoxed<'a, Q, DB>>
        + OrderDsl<Desc<Expr>, Output = IntoBoxed<'a, Q, DB>>,
{
    fn dyn_order(self, order: QueryOrdering, expr: Expr) -> IntoBoxed<'a, Q, DB> {
        order.order_query(self, expr)
    }
}

fn example<DB: Backend>(order: QueryOrdering) {
    order
        .order_query::<_, _, DB>(posts::table, posts::id)
        .limit(5);
    // want to do this instead
    posts::table.dyn_order(order, posts::id).limit(5);
}

The compiler shows this error

error[E0275]: overflow evaluating the requirement `Q: BoxedDsl<'_, Expr>`
  --> src/main.rs:48:23
   |
48 | impl<'a, Expr, DB, Q> DynOrderDsl<'a, Expr, DB> for Q
   |                       ^^^^^^^^^^^^^^^^^^^^^^^^^
   |
   = help: consider increasing the recursion limit by adding a `#![recursion_limit = "256"]` attribute to your crate (`databases`)
   = note: required for `Q` to implement `BoxedDsl<'_, Expr>`
   = note: 126 redundant requirements hidden
   = note: required for `Q` to implement `BoxedDsl<'_, Expr>`

As I see I somehow should tell the compiler that

susitsm
  • 465
  • 2
  • 6

1 Answers1

0

I got it in the end. The order of generic arguments in the impl of DynOrderDsl and the trait decralation was wrong. The final, working code:

I will post the final working code to the question I linked at the start.

susitsm
  • 465
  • 2
  • 6