如何使用 Diesel 设置 SQL 结果的日期格式?
How to date format an SQL result using Diesel?
我正在使用 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 带给我的数据?
当使用 ORM 时,数据以最合适的table 表示形式从数据库中提取,供 ORM 解释;之后您将在目标域中对其进行操作(在本例中为 rust)。
由于 date_sale
是 Option<NaiveDateTime>
,您可以使用 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 中更容易或更有效地实现的逻辑,这将更有用。
一个示例是过滤条件:假设您想要包含 table 中周数为偶数的行。虽然您可以加载整个 table 然后在 rust 域中过滤它,但效率不是很高。相反,您可以这样做:
let results = sales::table
.filter(sql("extract(week from date_sale)::smallint % 2=0"))
.load::<Sales>(&conn);
除了harmic
提供的答案外,还有两种可能解决这个问题。
sql_function!
Diesel 提供了一个接口,可以轻松地为 sql 函数定义查询 ast 节点,而 diesel 本身没有提供这些功能。鼓励用户使用此功能自行定义缺失的功能。 (事实上,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
派生提供了一种在加载时通过自定义属性应用特定类型操作的方法。结合 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()))
}
}
我正在使用 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 带给我的数据?
当使用 ORM 时,数据以最合适的table 表示形式从数据库中提取,供 ORM 解释;之后您将在目标域中对其进行操作(在本例中为 rust)。
由于 date_sale
是 Option<NaiveDateTime>
,您可以使用 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 中更容易或更有效地实现的逻辑,这将更有用。
一个示例是过滤条件:假设您想要包含 table 中周数为偶数的行。虽然您可以加载整个 table 然后在 rust 域中过滤它,但效率不是很高。相反,您可以这样做:
let results = sales::table
.filter(sql("extract(week from date_sale)::smallint % 2=0"))
.load::<Sales>(&conn);
除了harmic
提供的答案外,还有两种可能解决这个问题。
sql_function!
Diesel 提供了一个接口,可以轻松地为 sql 函数定义查询 ast 节点,而 diesel 本身没有提供这些功能。鼓励用户使用此功能自行定义缺失的功能。 (事实上,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
派生提供了一种在加载时通过自定义属性应用特定类型操作的方法。结合 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()))
}
}