我有一个REST端点,它从postgresql数据库中获取一些数据。其中一列是numeric类型的。当我获取数据时,它被序列化为文本,而不是带有小数点的数字。
#[derive(Serialize, Deserialize, QueryableByName)]
pub struct Product {
#[diesel(sql_type = Text)]
pub name: String,
#[diesel(sql_type = Numeric)]
pub price: BigDecimal,
}
impl Product {
pub fn find() -> Result<Vec<Product>, CustomError> {
let q = "
select
name,
price
from
products
order by
sales_count desc,
name asc
";
let mut conn = db::connection()?;
let p: Vec<Product> = diesel::sql_query(q)
.get_results(&mut conn)?;
Ok(p)
}
}
Cargo.toml:
diesel = { version = "2.0.2", features = ["postgres", "r2d2", "uuid", "chrono", "numeric", "serde_json"] }
serde = { version = "1.0.148", features = ["derive"] }
serde_json = "1.0.89"
bigdecimal = { version = "0.3.0", features = ["serde"] }
$ curl /products | jq
[
{
"name": "soda",
"price": "5.000"
},
{
"name": "ice",
"price": "4.000"
}
]
价格用于在客户端计算总和,将价格作为小数而不是文本将避免解析后的转换。我可以更改REST端点以发送数字/小数点的价格吗?
1条答案
按热度按时间vh0rcniy1#
正如@PitaJ所提到的,将
BigDecimal
s序列化为数字可能不是一个好主意,因为您的客户端不太可能能够处理任意精度。也就是说,这是可能的。serde_json
具有arbitrary_precision
特性。不方便的是,这并不能使BigDecimal
神奇地工作。在大多数情况下,它只是在内部将serde_json::Number
更改为String
,并添加一个内部特殊字段名称,这将导致String
在JSON中以数字形式发出。现在您可以滥用此功能并自己发出该内部字段名称,但更干净的是,我只需要将BigDecimal
转换为serde_json::Number
。可悲的是,serde_json::Number
和BigDecimal
彼此不信任,因此在它们之间转换的唯一方法是通过解析字符串。有了这些知识: