Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Rust diesel conditionally filter a query

I am trying to use diesel for a project and I would like to have a "filterable" type. The idea is that you can go to /api/foo?id=10&bar=11 and it would return a struct Foo:

struct Foo {
    id: Option<i64>,
    bar: Option<i64>,
    name: Option<String>,
}

Such as:

Foo {
   id: Some(10),
   bar: Some(11),
   name: None,
}

I've been scouring the internet for a way to filter by the fields that exist, but I am unable to find a solution that works. I was initially using the mysql driver and constructing sql queries with proc macros, but diesel is a lot nicer to work with and I was wondering if there was a way to get the same behaviour I had with the mysql driver with diesel.

like image 373
nadir Avatar asked Nov 27 '20 15:11

nadir


1 Answers

You can use the into_boxed method, which:

Boxes the pieces of a query into a single type. This is useful for cases where you want to conditionally modify a query, but need the type to remain the same. A boxed query will incur a minor performance penalty, as the query builder can no longer be inlined by the compiler. For most applications this cost will be minimal.

use crate::schema::foo;

let mut query = foo::table.into_boxed();

if let Some(id) = foo.id {
    query = query.filter(foo::id.eq(id));
}

if let Some(bar) = foo.bar {
    query = query.filter(foo::bar.eq(bar));
}

if let Some(name) = foo.name {
    query = query.filter(foo::name.eq(name));
}

let results = query
    .load::<Foo>(&conn)
    .expect("error loading foo");
like image 58
Ibraheem Ahmed Avatar answered Nov 13 '22 13:11

Ibraheem Ahmed