首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
MCP广场
社区首页 >问答首页 >序列化不是为PgRange<DateTime<Utc>>实现的

序列化不是为PgRange<DateTime<Utc>>实现的
EN

Stack Overflow用户
提问于 2022-07-06 07:38:46
回答 1查看 297关注 0票数 0

但是,我希望能够序列化包含PgRange<DateTime<Utc>>的结构,但是,#[derive(Serialize)]struct Reservation的错误失败:

代码语言:javascript
运行
复制
pub timespan: PgRange<DateTime<Utc>>,
^^^ the trait `Serialize` is not implemented for `PgRange<chrono::DateTime<chrono::Utc>>`

作为一种解决方法,我将timespan字段分成两个字段,用于序列化,但使SQL更加复杂。

数据方案如下:

代码语言:javascript
运行
复制
CREATE TABLE reservation (
    id INTEGER PRIMARY KEY GENERATED BY DEFAULT AS IDENTITY,
    timespan TSTZRANGE
);

INSERT INTO reservation(timespan) VALUES
    (TSTZRANGE(now() + INTERVAL '0 hour', now() + INTERVAL '1 hour')),
    (TSTZRANGE(now() + INTERVAL '2 hour', now() + INTERVAL '3 hour'));

还有我的工作代码示例:

代码语言:javascript
运行
复制
/*
[dependencies]
chrono = { version = "0.4", features = ["serde"] }
tokio = { version = "1", features = ["full"] }
sqlx = { version = "0.5", features = ["runtime-tokio-native-tls" , "postgres", "chrono"] }
serde = { version = "1.0", features = ["derive"] }
serde_json = "1.0"
*/

use chrono::prelude::*;
use serde::{Serialize, Deserialize};
use sqlx::FromRow;
use sqlx::postgres::types::PgRange;
use sqlx::postgres::PgPoolOptions;

#[derive(FromRow, Debug)]
pub struct Reservation {
    pub id: i32,
    pub timespan: PgRange<DateTime<Utc>>,
}

#[derive(FromRow, Serialize, Debug)]
pub struct ReservationWorkaroud {
    pub id: i32,
    pub start: DateTime<Utc>,
    pub end: DateTime<Utc>,
}

#[tokio::main]
async fn main() -> Result<(), sqlx::Error> {

    let pool = PgPoolOptions::new()
        .max_connections(2)
        .connect(&"postgresql://postgres:postgres@localhost")
        .await?;


    // Ideally, I would like my struct to mirror db table as close as possible while being able to serialize/deserialize to/from Json
    let select_query = sqlx::query_as::<_, Reservation>("SELECT id, timespan FROM reservation");
    let reservations: Vec<Reservation> = select_query.fetch_all(&pool).await?;
    dbg!("{:?}", reservations);


    // With the workaroud struct, I am able to serialize it however, sql queries start to get complex especially for inserting:
    let select_query = sqlx::query_as::<_, ReservationWorkaroud>("SELECT id, lower(timespan) AS start, upper(timespan) AS end  FROM reservation");
    let reservations: Vec<ReservationWorkaroud> = select_query.fetch_all(&pool).await?;
    dbg!("{:?}", reservations);

    Ok(())
}

如何使struct Reservation可序列化?

更新

基于@恺撒的回答,我采用了以下方法:

代码语言:javascript
运行
复制
#[derive(FromRow, Serialize,Debug)]
pub struct Reservation {
    pub id: i32,
    #[serde(serialize_with = "serialize_range", flatten)]
    pub timespan: PgRange<DateTime<Utc>>,
}

fn serialize_range<S, T>(range: &PgRange<T>, serializer: S) -> Result<S::Ok, S::Error>
where
    S: serde::Serializer,
    T: Serialize,
{
    let PgRange { start, end } = range;
    std::ops::Range { start, end }.serialize(serializer)
}
EN

回答 1

Stack Overflow用户

回答已采纳

发布于 2022-07-07 01:54:45

关于这一点,有很多种方法可以继续下去。

  1. 我最喜欢的serde技巧,使用容器属性 #[serde(into = "ReservationWorkaround")] on struct Reservation并添加一个impl Into<ReservationWorkaround> for Reservation {}。有关使用属性的示例,请参见这里
  2. 使用自定义序列化函数
代码语言:javascript
运行
复制
#[derive(FromRow, Debug, Serialize)]
pub struct Reservation {
    pub id: i32,
    #[serde(serialize_with = "serialize_range", flatten)]
    pub timespan: PgRange<DateTime<Utc>>,
}

fn serialize_range<S, T>(range: &PgRange<T>, serializer: S) -> Result<S::Ok, S::Error>
where
    S: serde::Serializer,
    T: Serialize,
{
    // You probably also want to convert start and end
    // from Bound<DateTime<Utc>> to something else here.
    // It is common to define a new struct like
    #[derive(Serialize)] struct I64Range { start: i64, end: i64 }
    // right here in this function
    let PgRange { start, end } = range;
    std::ops::Range { start, end }.serialize(serializer)
}
  1. 理论上,这是“远程派生”的主要用例,但是您必须想出一个单独的解决方案来转换Bound<DateTime<Utc>>。也许serde_with箱子能帮上忙,但我不确定。
代码语言:javascript
运行
复制
#[derive(FromRow, Debug, Serialize)]
pub struct Reservation {
    pub id: i32,
    #[serde(with = "PgRangeRemote", flatten)]
    pub timespan: PgRange<DateTime<Utc>>,
}

#[derive(Serialize)]
#[serde(remote = "PgRange")]
struct PgRangeRemote<T> {
    start: std::ops::Bound<T>,
    end: std::ops::Bound<T>,
}
票数 1
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/72879584

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档