如何根据 Diesel 的动态参数有条件地按列排序?

Posted

技术标签:

【中文标题】如何根据 Diesel 的动态参数有条件地按列排序?【英文标题】:How do I conditionally order by a column based on a dynamic parameter with Diesel? 【发布时间】:2020-04-05 01:04:57 【问题描述】:

我正在尝试根据外部参数为 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 支持来显示在我的 IDE 中输入任何 schema::items::dsl::* 类型,这样我就可以自己打乱了。

【问题讨论】:

把 if 放在最上面并在每个手臂上做一个匹配应该节省一些行 【参考方案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 if 以下函数

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
    

【讨论】:

以上是关于如何根据 Diesel 的动态参数有条件地按列排序?的主要内容,如果未能解决你的问题,请参考以下文章

根据列中的值按列动态排序

使用动态参数查询 Diesel 表

如何在动态数据透视中先按行排序,然后按列排序

如何从辅助方法动态返回 Diesel 等式表达式?

如果单击标题视图,如何在表格视图中按列对数据进行排序

如何按列对二维数组(锯齿状)进行排序[重复]