Conditional query building in function

Hi everyone,

I’m relatively new to Rust and I’m having a hard time implementing a function that builds a conditional query and returns the result mutable.

#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct QueryRequest<T: Clone + QueryFilter> {
  pub _limit: Option<i64>,
  pub _offset: Option<i64>,
  pub _fields: Option<Vec<String>>,
  pub _order: Option<Vec<String>>,
  pub _filter: T
}

impl<T: Clone + QueryFilter> QueryRequest<T> {
  pub fn query<'a, QS, DB> (&self, table: &'a QS) -> &'a mut BoxedSelectStatement<'a, QS::SqlType, QS, DB>
  where
    QS: Table,
    DB: Backend + HasSqlType<QS::SqlType> {

    let mut dsl = table.into_boxed();

    dsl = dsl.filter(diesel::dsl::sql(&self._filter.sql())).into_boxed();

    if let Some(v) = self._limit {
      dsl = dsl.limit(v).into_boxed();
    }

    if let Some(v) = self._offset {
      dsl = dsl.offset(v).into_boxed();
    }

    dsl.into_boxed()
  }
}

let mut query = query_request.query(&users::table);
// or
let mut query = query_request.query(&users::table.select(/*columns*/));

I tried several combinations of traits but I always end up getting an recursion error:

error[E0275]: overflow evaluating the requirement `_: std::marker::Sized`
  --> src/models/query.rs:24:25
   |
24 |     let mut dsl = table.into_boxed();
   |                         ^^^^^^^^^^
   |
   = help: consider adding a `#![recursion_limit="512"]` attribute to your crate (`...`)
   = note: required because of the requirements on the impl of `diesel::query_dsl::boxed_dsl::BoxedDsl<'_, _>` for `<QS as diesel::query_builder::AsQuery>::
Query`

Or other problems like rust not finding the methods filter, limit and offset.

Can someone tell me what I am doing wrong or point me to a place in the docs or the source of diesel?

Furthermore, maybe there is a better approach to what I’m trying to do and I believe so, considering the few ressources I found about this topic?

I found the solution for my problem:

use diesel::query_builder::*;
use diesel::query_dsl::filter_dsl::FilterDsl;
use diesel::query_source::QuerySource;
use diesel::backend::Backend;

pub trait FilterQueryDsl<'a, DB, ST, QF>
  where
    DB: Backend,
    QF: QueryFilter {
  fn filter_query (self, qr: &QF) -> Self;
}

impl<'a, DB, ST, QF, QS> FilterQueryDsl<'a, DB, ST, QF> for BoxedSelectStatement<'a, ST, QS, DB>
  where
    DB: 'a,
    DB: Backend,
    QS: QuerySource,
    QF: QueryFilter {

  fn filter_query (self, qr: &QF) -> Self {
    let mut query = self;

    for item in qr.query_items().iter() {
      let (field, constraint) = prepare_filter_query(item);
      query = query.filter(diesel::dsl::sql(&format!(r#""{}"{}"#, field, constraint)));
    }

    query
  }
}

This adds a new builder function to diesel what is satisfying for me now and better than the solution proposed in my question.

I am not fully satisfied with this solution but I render the issue solved and therefore close this entry.