您将如何为 Postgres Jsonb 类型设置 FromSql 和 ToSql 的 impl 函数,它可以是数据数组

How would you setup the impl functions of FromSql and ToSql for a Postgres Jsonb type, that can be an array of data

您将如何为 Postgres Jsonb 类型设置 FromSql 和 ToSql 的 impl 函数,它可以是数据数组。

下面是一些示例数组 json 数据。

[
    {
        "title": "some text",
        "date_str": null,
    },
    {
        "title": "some more text",
        "date_str": "Feb 25th",
    },
]

这是我目前拥有的代码。我能够毫无问题地找出 none 数组实现,但我正在努力为包装类型 (Vec) 创建 ToSql 和 FromSql。我收到错误“Error(DeserializationError(error("invalid type: map, expaected a sequence", line: 0, column: 0)))”,我不确定我需要做什么更改。

// models.rs
#[derive(Debug, Serialize, Deserialize, Queryable, QueryableByName)]
#[table_name = "table"]
pub struct table {
    pub id: i32,
    pub cust_jsonb: CustJsonbs,
}

#[derive(FromSqlRow, AsExpression, Debug, Serialize, Deserialize)]
#[sql_type = "Jsonb"]
pub struct CustJsonb {
    pub title: String,
    pub date_arg: Option<String>,
}

//wrapper type
#[derive(FromSqlRow, AsExpression, Debug, Serialize, Deserialize)]
#[sql_type = "Jsonb"]
pub struct CustJsonbs (
    Vec<CustJsonb>
);

// None array implementation that works
impl FromSql<Jsonb, Pg> for CustJsonb {
    fn from_sql(bytes: Option<&[u8]>) -> diesel::deserialize::Result<Self> {
        let value = <serde_json::Value as FromSql<Jsonb, Pg>>::from_sql(bytes)?;
        Ok(serde_json::from_value(value)?)
    }
}

impl ToSql<Jsonb, Pg> for CustJsonb {
    fn to_sql<W: Write>(&self, out: &mut Output<W, Pg>) -> diesel::serialize::Result {
        let value = serde_json::to_value(self)?;
        <serde_json::Value as ToSql<Jsonb, Pg>>::to_sql(&value, out)
    }
}

// Array implementation - I've tried (doesn't work and not sure how to fix it exactly)
impl FromSql<Jsonb, Pg> for CustJsonbs {
    fn from_sql(bytes: Option<&[u8]>) -> diesel::deserialize::Result<Self> {
        let value = <serde_json::Value as FromSql<Jsonb, Pg>>::from_sql(bytes)?;
        Ok(serde_json::from_value(value)?)
    }
}

impl ToSql<Jsonb, Pg> for CustJsonbs {
    fn to_sql<W: Write>(&self, out: &mut Output<W, Pg>) -> diesel::serialize::Result {
        let value = serde_json::to_value(self)?;
        <serde_json::Value as ToSql<Jsonb, Pg>>::to_sql(&value, out)
    }
}

所以这个问题的答案很简单。

impl FromSql<Jsonb, Pg> for CustJsonbs {
    fn from_sql(bytes: Option<&[u8]>) -> diesel::deserialize::Result<Self> {
        let value = <serde_json::Value as FromSql<Jsonb, Pg>>::from_sql(bytes)?;
        Ok(serde_json::from_value(value)?)
    }
}

此函数的最后一行指示直接从返回值构造结构。这失败了,因为返回的值是一个数组而不是结构,如错误消息所示。

固定版本只会从 json 值构造内部数组并手动添加外部新类型包装器。

impl FromSql<Jsonb, Pg> for CustJsonbs {
    fn from_sql(bytes: Option<&[u8]>) -> diesel::deserialize::Result<Self> {
        let value = <serde_json::Value as FromSql<Jsonb, Pg>>::from_sql(bytes)?;
        Ok(Self(serde_json::from_value(value)?)) 
        // ^^^^ note the additional `Self` there
        // Thats required to tell serde that we only want
        // to construct the inner array from the provided json
    }
}
``