diff --git a/changelog/master.md b/changelog/master.md index 3f74cba6..5aa87418 100644 --- a/changelog/master.md +++ b/changelog/master.md @@ -6,3 +6,13 @@ **Note:** while this is not a Rust breaking change, if you relied on the serialization format (perhaps by storing serialized data in a database or making asumptions in your client code written in another language) it could be a breaking change for your application. [#151](https://github.com/graphql-rust/juniper/pull/151) + +* Large integers (> signed 32bit) are now deserialized as floats. Previously, + they produced the "integer out of range" error. For languages that do not + have distinction between integer and floating point types (including + javascript), this means large floating point values which do not have + fractional part could not be decoded (because they are represented without + a decimal part `.0`). + + [#179](https://github.com/graphql-rust/juniper/pull/179) + diff --git a/juniper/src/integrations/serde.rs b/juniper/src/integrations/serde.rs index 72b96ef8..72048c79 100644 --- a/juniper/src/integrations/serde.rs +++ b/juniper/src/integrations/serde.rs @@ -79,7 +79,12 @@ impl<'de> de::Deserialize<'de> for InputValue { if value >= i64::from(i32::min_value()) && value <= i64::from(i32::max_value()) { Ok(InputValue::int(value as i32)) } else { - Err(E::custom("integer out of range")) + // Browser's JSON.stringify serialize all numbers having no + // fractional part as integers (no decimal point), so we + // must parse large integers as floating point otherwise + // we would error on transferring large floating point + // numbers. + Ok(InputValue::float(value as f64)) } } @@ -90,7 +95,12 @@ impl<'de> de::Deserialize<'de> for InputValue { if value <= i32::max_value() as u64 { self.visit_i64(value as i64) } else { - Err(E::custom("integer out of range")) + // Browser's JSON.stringify serialize all numbers having no + // fractional part as integers (no decimal point), so we + // must parse large integers as floating point otherwise + // we would error on transferring large floating point + // numbers. + Ok(InputValue::float(value as f64)) } } @@ -247,3 +257,24 @@ impl ser::Serialize for Value { } } } + +#[cfg(test)] +mod tests { + use serde_json::from_str; + use ast::InputValue; + + #[test] + fn int() { + assert_eq!(from_str::("1235").unwrap(), + InputValue::int(1235)); + } + + #[test] + fn float() { + assert_eq!(from_str::("2.0").unwrap(), + InputValue::float(2.0)); + // large value without a decimal part is also float + assert_eq!(from_str::("123567890123").unwrap(), + InputValue::float(123567890123.0)); + } +}