TLDR:给定一个包含Json数组的列返回行的查询:
id | name | post_ids
----+---------+----------
1 | JohnDoe | [1,2]使用tokio_postgres将其序列化到User模型-which中包含一个post_ids: Vec<i32>字段--似乎是不可能的。
#[derive(Debug, Serialize, Deserialize, JsonSchema)]
pub struct User {
pub id: String,
pub name: String,
pub post_ids: Vec<i32>
}尝试为tokio_postgres::types::FromSql实现i32,但它只允许用于结构。
我想知道在这个Json和Vec<i32>之间转换的常见方式是什么。
包含完整代码的长版本:
我有一个带有User和Post模型的Postgres数据库:
id | name
----+---------
1 | JohnDoe id | title | user_id
----+-------------+---------
1 | first post | 1
2 | second post | 1我有一个函数来检索用户以及数据库中的帖子。我知道我可以做得更好,但我的问题是这个函数返回的是posts_ids:
create function user_get_one(
user_id int
)
returns table (
"id" text,
"name" text,
post_ids json
) AS $$
select
"user"."id",
"user"."name",
(select to_json(array_agg("posts"."id"))
from (
select
"id"
from
"post"
where
"post"."user_id" = user_id
) posts
) posts_ids
from "user"
where
"user".id = user_id;
$$ language sql;这里是一个包含所有DB的小提琴。
现在,为了测试目的,我想要一个Rust中的API,它连接到这个DB,调用这个函数,实例化适当的模型,并在控制台中打印数据,不返回任何内容:
Cargo.toml:
[package]
name = "test"
version = "0.1.0"
edition = "2018"
[dependencies]
tokio-postgres = "0.7.5"
tokio = { version = "1.14.0", features = ["full"] }进口:
use tokio_postgres::{NoTls, Row};模型:
#[derive(Debug, Serialize, Deserialize, JsonSchema)]
pub struct User {
pub id: String,
pub name: String,
// pub post_ids: Vec<i32>, // Uncomment
}
impl From<Row> for User {
fn from(row: Row) -> Self {
Self {
id: row.get("id"),
name: row.get("name"),
// post_ids: row.get("post_ids"), // Uncomment
}
}
}其主要职能如下:
#[tokio::main]
async fn main() -> () {
let (client, connection) = tokio_postgres::connect(
"postgresql://localhost/rc_forum?user=test_user&password=secret_password ",
NoTls,
)
.await
.unwrap();
tokio::spawn(async move {
if let Err(e) = connection.await {
eprintln!("connection error: {}", e);
}
});
// Now we can execute a simple statement that just returns its parameter.
let result = client
.query_one("select * from user_get_one($1)", &[&1])
.await
.unwrap();
let user: User = User::from(result);
println!("-----------");
println!("{:#?}", user);
println!("-----------");
}以下是锈菌操场的完整代码:https://play.rust-lang.org/?version=stable&mode=debug&edition=2021&gist=677a4f7710f6a29c7e33d3228679881f
现在,有了posts_ids注释,用户就被加载并实例化了;但是,如果我们取消注释posts_ids,postgres_tokio就不能转换类型:
error retrieving column post_ids: error deserializing column 2:
cannot convert between the Rust type `alloc::vec::Vec<i32>` and the Postgres type `json`',在这个Json和Vec<i32>之间转换的通用方式是什么?
发布于 2022-05-24 23:52:03
我对Rust或tokio_postgres不太了解,但我想认为锈蚀矢量基本上是一个可以增长的数组--相当于Postgres数组。Vec<i32>是四字节整数的锈蚀向量.我认为这不能接受Postgres的json值。使用整数的Postgres数组(int[])代替:
在此过程中,我将您的复杂功能简化了一点:
CREATE FUNCTION user_get_one(_user_id int)
RETURNS TABLE (id text, name text, post_ids int[])
LANGUAGE sql AS
$func$
SELECT u.id
, u.name
, ARRAY(SELECT p.id FROM post p
WHERE p.user_id = _user_id) AS posts_ids
FROM "user" u -- very unfortunate name!
WHERE u.id = _user_id;
$func$;db<>fiddle https://dbfiddle.uk/?rdbms=postgres_14&fiddle=61a61b5f102259498939b2ed26e25908
关于数组构造函数:
我将向子查询中添加一个ORDER BY子句,以获得一个确定的结果。否则,下一个调用可能使用不同的排序顺序报告相同的数组。所以:
...
, ARRAY(SELECT p.id FROM post p
WHERE p.user_id = _user_id ORDER BY 1) AS posts_ids
...如果您已经有了一个JSON数组,下面是如何转换它:
旁白:不要像“用户”一样使用保留字作为Postgres标识符。
https://stackoverflow.com/questions/72370262
复制相似问题