【问题标题】:How to date format an SQL result using Diesel?如何使用 Diesel 格式化 SQL 结果?
【发布时间】:2020-08-08 14:58:47
【问题描述】:

我正在使用 Diesel 通过 JOIN 查询 PostgreSQL 中的数据库:

let product_id = 1;
sales::table
     .inner_join(product::table)
     .select((
         product::description,
         sales::amount,
         sales::date_sale
     ))
     .filter(sales::product_id.eq(product_id))
     .load(&diesel::PgConnection)

我的模特:

pub struct Sales {
    pub id: i32,
    pub product_id: Option<i32>,
    pub amount: Option<BigDecimal>,
    pub date_sale: Option<NaiveDateTime>
}

结果符合预期,但我需要为字段 sales::date_sale 提供日期格式,在 pgadmin 中我使用 to_char(date_sale, 'dd/mm/YYYY') 执行此操作。

是否可以在 Diesel 中使用 to_char 或者我可以通过什么方式修改 Diesel ORM 带给我的数据?

【问题讨论】:

    标签: rust rust-diesel


    【解决方案1】:

    当使用 ORM 时,数据以最适合 ORM 解释的表示从数据库中提取;之后,您将在目标域中对其进行操作(在本例中为 rust)。

    由于date_saleOption&lt;NaiveDateTime&gt;,您可以使用chrono 提供的格式选项:

    sale.date_sale.unwrap().format("%d/%m/%Y").to_string()
    

    (当然,您的真实代码不会使用unwrap()!)

    或者,如果您确实需要数据库进行格式化,您可以使用[sql][2] 在查询中插入一些原始 SQL:

    let results = sales::table.select((sales::id, sql("to_char(date_sale, 'dd/mm/YYYY')")))
        .load::<(i32, String)>(&conn);
    

    如果您尝试实现一些在 SQL 中更容易或更有效地实现的逻辑,这将更加有用。

    一个示例是过滤条件:假设您想包含表中周数为偶数的行。虽然您可以加载整个表,然后在 rust 域中对其进行过滤,但这并不是很有效。相反,您可以这样做:

    let results = sales::table
        .filter(sql("extract(week from date_sale)::smallint % 2=0"))
        .load::<Sales>(&conn);
    

    【讨论】:

      【解决方案2】:

      除了harmic提供的答案之外,还有两种可能解决这个问题。

      sql_function!

      Diesel 提供了一个接口,可以轻松地为柴油本身不提供的 sql 函数定义查询 ast 节点。鼓励用户使用此功能自行定义缺失的功能。 (事实上​​,diesel 在内部使用相同的方法为开箱即用的 sql 函数定义查询 ast 节点)。定义的查询 ast 节点可在其表达式类型有效的每个上下文中使用,因此它可以在 select 和 where 子句中使用。 (这基本上是上面原始 sql 解决方案的类型安全版本)

      对于给定的问题,这样的事情应该有效:

      #[derive(Queryable)]
      pub struct Sales {
          pub id: i32,
          pub product_id: Option<i32>,
          pub amount: Option<BigDecimal>,
          pub date_sale: Option<String>,
      }
      
      sql_function! {
          fn to_char(Nullable<Timestamp>, Text) -> Nullable<Text>;
      }
      
      let product_id = 1;
      sales::table
           .inner_join(product::table)
           .select((
               product::description,
               sales::amount,
               to_char(sales::date_sale, "dd/mm/YYYY")
           ))
           .filter(sales::product_id.eq(product_id))
           .load(&diesel::PgConnection);
      
      

      #[derive(Queryable)] + #[diesel(deserialize_as = "Type")]

      Diesels Queryable derived 提供了一种在加载时通​​过自定义属性应用某些类型操作的方法。结合harmic 提供的chrono 解决方案,这给出了以下变体:

      #[derive(Queryable)]
      pub struct Sales {
          pub id: i32,
          pub product_id: Option<i32>,
          pub amount: Option<BigDecimal>,
          #[diesel(deserialize_as = "MyChronoTypeLoader")]
          pub date_sale: Option<String>
      }
      
      struct MyChronoTypeLoader(Option<String>);
      
      impl Into<Option<String>> for MyChronoTypeLoader {
          fn into(self) -> String {
              self.0
          }
      }
      
      impl<DB, ST> Queryable<ST, DB> for MyChronoTypeLoader
      where
          DB: Backend,
          Option<NaiveDateTime>: Queryable<ST, DB>,
      {
          type Row = <Option<NaiveDateTime> as Queryable<ST, DB>>::Row;
      
          fn build(row: Self::Row) -> Self {
              MyChronoTypeLoader(Option::<NaiveDateTime>::build(row).map(|d| d.format("%d/%m/%Y").to_string()))
          }
      }
      

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 2014-06-02
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2022-01-19
        • 2017-09-16
        • 1970-01-01
        相关资源
        最近更新 更多