juniper/integrations/
rust_decimal.rs1use crate::{ScalarValue, graphql_scalar};
12
13#[graphql_scalar]
28#[graphql(
29 with = rust_decimal_scalar,
30 to_output_with = ScalarValue::from_displayable,
31 parse_token(i32, f64, String),
32 specified_by_url = "https://docs.rs/rust_decimal",
33)]
34type Decimal = rust_decimal::Decimal;
35
36mod rust_decimal_scalar {
37 use super::Decimal;
38 use crate::{Scalar, ScalarValue};
39
40 pub(super) fn from_input(v: &Scalar<impl ScalarValue>) -> Result<Decimal, Box<str>> {
41 if let Some(i) = v.try_to_int() {
42 Ok(Decimal::from(i))
43 } else if let Some(f) = v.try_to_float() {
44 Decimal::try_from(f)
45 .map_err(|e| format!("Failed to parse `Decimal` from `Float`: {e}").into())
46 } else {
47 v.try_to::<&str>()
48 .map_err(|e| e.to_string().into())
49 .and_then(|s| {
50 s.parse::<Decimal>()
51 .map_err(|e| format!("Failed to parse `Decimal` from `String`: {e}").into())
52 })
53 }
54 }
55}
56
57#[cfg(test)]
58mod test {
59 use crate::{FromInputValue as _, InputValue, ToInputValue as _, graphql_input_value};
60
61 use super::Decimal;
62
63 #[test]
64 fn parses_correct_input() {
65 for (input, expected) in [
66 (graphql_input_value!("4.20"), "4.20"),
67 (graphql_input_value!("0"), "0"),
68 (graphql_input_value!("999.999999999"), "999.999999999"),
69 (graphql_input_value!("875533788"), "875533788"),
70 (graphql_input_value!(123), "123"),
71 (graphql_input_value!(0), "0"),
72 (graphql_input_value!(43.44), "43.44"),
73 ] {
74 let input: InputValue = input;
75 let parsed = Decimal::from_input_value(&input);
76 let expected = expected.parse::<Decimal>().unwrap();
77
78 assert!(
79 parsed.is_ok(),
80 "failed to parse `{input:?}`: {:?}",
81 parsed.unwrap_err(),
82 );
83 assert_eq!(parsed.unwrap(), expected, "input: {input:?}");
84 }
85 }
86
87 #[test]
88 fn fails_on_invalid_input() {
89 for input in [
90 graphql_input_value!(""),
91 graphql_input_value!("0,0"),
92 graphql_input_value!("12,"),
93 graphql_input_value!("1996-12-19T14:23:43"),
94 graphql_input_value!("99999999999999999999999999999999999999"),
95 graphql_input_value!("99999999999999999999999999999999999999.99"),
96 graphql_input_value!("i'm not even a number"),
97 graphql_input_value!(null),
98 graphql_input_value!(false),
99 ] {
100 let input: InputValue = input;
101 let parsed = Decimal::from_input_value(&input);
102
103 assert!(parsed.is_err(), "allows input: {input:?}");
104 }
105 }
106
107 #[test]
108 fn formats_correctly() {
109 for raw in ["4.20", "0", "999.999999999", "875533788", "123", "43.44"] {
110 let actual: InputValue = raw.parse::<Decimal>().unwrap().to_input_value();
111
112 assert_eq!(actual, graphql_input_value!((raw)), "on value: {raw}");
113 }
114 }
115}