2

我正在尝试order_by根据外部参数指定不同的列。

这有效,但很难看:

#[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() {}

我的 Cargo.toml 有这个:

[dependencies]
diesel = { version = "1.4.3", features = ["postgres"] }

我只想按列而不是整个查询来设置条件,例如:

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");

这可能吗?有没有其他方法可以重构这个?

我已经阅读Querying a Diesel table with dynamic parameters,但它基本上是关于整个查询的条件,这是我试图避免的。

我还阅读了 Creating Diesel.rs queries with a dynamic number of .and()'s,这是关于过滤条件的。这可能与我所需要的很接近order_by,但我很难将这种BoxableExpression奇怪之处应用到我的案例中,因为文档中缺少针对我的确切案例的好例子,并且缺少 RLS 支持schema::items::dsl::*在我的 IDE 中显示任何类型,这样我就可以自己爬过去了。

4

1 回答 1

1

给定以下架构:

table! {
    flights (id) {
        id -> Int4,
        name -> Text,
        country -> Text,
        launch_date -> Timestamptz,
    }
}

以下结构包含排序选项:

pub struct SearchFlight {
    pub sort: Option<String>,
    pub sort_dir: Option<String>
}

可以执行以下操作:

let mut query = flights.into_boxed();
match search.sort.as_ref().map(String::as_str)  {
    Some("name") => sort_by_column(query, flights_schema::name, search.sort_dir),
    Some("country") => sort_by_column(query, flights_schema::country, search.sort_dir),
    Some("launch_date") => sort_by_column(query, flights_schema::launch_date, search.sort_dir),
    _ => query
}
query.load_page::<Flight>(con)

where sort_by_column 如果以下函数

fn sort_by_column<U: 'static>(mut query: BoxedQuery<'static, Pg>,
                     column: U,
                     sort_dir: Option<String>) -> BoxedQuery<'static, Pg>
    where U: ExpressionMethods + QueryFragment<Pg> + AppearsOnTable<flights_schema::table>{
    match sort_dir.as_ref().map(String::as_str) {
        Some("asc") => query.order_by(column.asc()),
        Some("desc") => query.order_by(column.desc()),
        _ => query
    }
}
于 2020-05-26T19:21:54.693 回答