This is an example of what I would like to achieve without resorting to custom Scalar:
/*
[dependencies]
async-graphql = { version = "7.0.11", default-features = false, features = [
"decimal",
] }
rust_decimal = { version = "1.36.0", features = [
"serde-with-arbitrary-precision",
] }
serde = { version = "1.0.215", default-features = false }
serde_json = { version = "1.0.133", default-features = false }
tokio = { version = "1.42.0", features = ["full"] }
*/
use async_graphql::{Context, Object, Scalar, ScalarType, Schema, SimpleObject, Value};
use rust_decimal::Decimal;
use std::str::FromStr;
#[derive(serde::Serialize, serde::Deserialize)]
struct MyDecimal(Decimal);
#[Scalar]
impl ScalarType for MyDecimal {
fn parse(value: Value) -> async_graphql::InputValueResult<Self> {
if let Value::String(s) = value {
Ok(MyDecimal(
Decimal::from_str(&s).map_err(|_| "Invalid decimal value")?,
))
} else {
Err("Invalid type for Decimal".into())
}
}
fn to_value(&self) -> Value {
if let Ok(n) = serde_json::Number::from_str(&self.0.to_string()) {
Value::Number(n)
} else {
Value::String(self.0.to_string())
}
}
}
#[derive(SimpleObject, serde::Serialize, serde::Deserialize)]
pub struct CustomTax {
percentage: MyDecimal,
}
#[derive(SimpleObject, serde::Serialize, serde::Deserialize)]
pub struct Tax {
#[serde(with = "rust_decimal::serde::arbitrary_precision")]
percentage: Decimal,
}
struct QueryRoot;
#[Object]
impl QueryRoot {
async fn get_tax(&self, _ctx: &Context<'_>) -> Tax {
Tax {
percentage: Decimal::from_str("123.400").unwrap(),
}
}
async fn get_custom_tax(&self, _ctx: &Context<'_>) -> CustomTax {
CustomTax {
percentage: MyDecimal(Decimal::from_str("123.400").unwrap()),
}
}
}
#[tokio::main]
async fn main() {
// let value = Tax {
// name: "Pay".to_string(),
// percentage: Decimal::from_str("123.400").unwrap(),
// };
// assert_eq!(
// &serde_json::to_string(&value).unwrap(),
// r#"{"name":"Pay","percentage":123.400}"#
// );
// --------
let schema = Schema::new(
QueryRoot,
async_graphql::EmptyMutation,
async_graphql::EmptySubscription,
);
let query = "{ getTax { percentage } getCustomTax { percentage } }";
let response = schema.execute(query).await;
println!("{}", serde_json::to_string_pretty(&response).unwrap());
assert_eq!(
r#"{getTax: {percentage: 123.400}, getCustomTax: {percentage: 123.400}}"#,
response.data.to_string(),
);
// I'm getting instead: {getTax: {percentage: \"123.400\"}, getCustomTax: {percentage: 123.400}}
}
Why the #[serde(with = "rust_decimal::serde::arbitrary_precision")]
is not working?