tokio_postgres:将Json序列化为Vec<i32>
tokio_postgres: serialize Json into Vec<i32>
TLDR:
给定一个查询,其中 returns 行的列包含 Json 数组:
id | name | post_ids
----+---------+----------
1 | JohnDoe | [1,2]
使用 tokio_postgres
将其序列化到包含 post_ids: Vec<i32>
字段的 User
模型中似乎是不可能的。
#[derive(Debug, Serialize, Deserialize, JsonSchema)]
pub struct User {
pub id: String,
pub name: String,
pub post_ids: Vec<i32>
}
尝试为 i32
实现 tokio_postgres::types::FromSql
,但它只允许用于结构。
我想知道这个 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;
这是一个包含所有数据库的 fiddle。
现在,出于测试目的,我想要一个 Rust 中的 API 连接到此数据库,调用此函数,实例化适当的模型并在控制台中打印数据,不返回任何内容:
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])
.await
.unwrap();
let user: User = User::from(result);
println!("-----------");
println!("{:#?}", user);
println!("-----------");
}
这里是 Rust playground 中的完整代码: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>
的常用转换方式是什么?
我不太了解 Rust 或 tokio_postgres,但是 I gather RUST vector 基本上是一个可以增长大小的数组 -相当于 Postgres array。 Vec<i32>
是一个 RUST 4 字节整数向量 。我认为这不能采用 Postgres json
值。使用整数 (int[]
) 的 Postgres 数组代替:
在做的时候,我稍微简化了你的复杂函数:
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 here
关于 ARRAY 构造函数:
我会在子查询中添加一个 ORDER BY
子句以获得确定性结果。否则,下一次调用可能会报告具有不同排序顺序的相同数组。所以:
...
, ARRAY(SELECT p.id FROM post p
WHERE p.user_id = _user_id ORDER BY 1) AS posts_ids
...
如果您已经有一个JSON数组,下面是转换它的方法:
旁白:不要使用 reserved words 之类的“用户”作为 Postgres 标识符。
TLDR: 给定一个查询,其中 returns 行的列包含 Json 数组:
id | name | post_ids
----+---------+----------
1 | JohnDoe | [1,2]
使用 tokio_postgres
将其序列化到包含 post_ids: Vec<i32>
字段的 User
模型中似乎是不可能的。
#[derive(Debug, Serialize, Deserialize, JsonSchema)]
pub struct User {
pub id: String,
pub name: String,
pub post_ids: Vec<i32>
}
尝试为 i32
实现 tokio_postgres::types::FromSql
,但它只允许用于结构。
我想知道这个 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;
这是一个包含所有数据库的 fiddle。
现在,出于测试目的,我想要一个 Rust 中的 API 连接到此数据库,调用此函数,实例化适当的模型并在控制台中打印数据,不返回任何内容:
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])
.await
.unwrap();
let user: User = User::from(result);
println!("-----------");
println!("{:#?}", user);
println!("-----------");
}
这里是 Rust playground 中的完整代码: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>
的常用转换方式是什么?
我不太了解 Rust 或 tokio_postgres,但是 I gather RUST vector 基本上是一个可以增长大小的数组 -相当于 Postgres array。 Vec<i32>
是一个 RUST 4 字节整数向量 。我认为这不能采用 Postgres json
值。使用整数 (int[]
) 的 Postgres 数组代替:
在做的时候,我稍微简化了你的复杂函数:
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 here
关于 ARRAY 构造函数:
我会在子查询中添加一个 ORDER BY
子句以获得确定性结果。否则,下一次调用可能会报告具有不同排序顺序的相同数组。所以:
...
, ARRAY(SELECT p.id FROM post p
WHERE p.user_id = _user_id ORDER BY 1) AS posts_ids
...
如果您已经有一个JSON数组,下面是转换它的方法:
旁白:不要使用 reserved words 之类的“用户”作为 Postgres 标识符。