I'm trying to specify different columns for order_by
depending on an external parameter.
This works, but is ugly:
#[macro_use]
extern crate diesel;
use crate::diesel::prelude::*;
use diesel::pg::PgConnection;
mod schema {
table! {
items (id) {
id -> Int4,
name -> Text,
}
}
}
#[derive(Queryable, Debug)]
pub struct Item {
pub id: i32,
pub name: String,
}
fn load_items(conn: PgConnection, sort_prop: String, sort_dir: String) -> Vec<Item> {
use schema::items::dsl::*;
let mut query = items.into_boxed();
// ugly: duplicating condition by sort_dir and query.order_by() calls
query = match sort_prop.as_str() {
"name" => {
if sort_dir == "asc" {
query.order_by(name.asc())
} else {
query.order_by(name.desc())
}
}
_ => {
if sort_dir == "asc" {
query.order_by(id.asc())
} else {
query.order_by(id.desc())
}
}
};
query.load::<Item>(&conn).expect("Failed to load items")
}
fn main() {}
My Cargo.toml has this:
[dependencies]
diesel = { version = "1.4.3", features = ["postgres"] }
I want to condition only by column, and not entire query, something like:
use schema::items::dsl::*;
let mut column = match sort_prop.as_str() {
"name" => name,
_ => id // error: match arms have incompatible types
}
column = if sort_dir == "asc" {
column.asc()
} else {
column.desc()
}
let results = items
.order_by(column)
.load::<Item>(connection)
.expect("Failed to load items");
Is this possible? Is there any other way to refactor this?
I've read Querying a Diesel table with dynamic parameters, but it's basically about conditioning by the entire query, which is what I'm trying to avoid.
I've also read Creating Diesel.rs queries with a dynamic number of .and()'s, which is about conditioning by filter. This might be close to what I need with order_by
, but it's hard for me to apply the BoxableExpression
weirdness to my case because there's a lack of good examples for my exact case in the docs and a lack of RLS support for showing any schema::items::dsl::*
types in my IDE, so I could scramble through myself.