Replace Value::Int and Value::Float with Value::Number.

This commit is contained in:
Sunli 2020-07-28 22:13:07 +08:00
parent 01233a9c28
commit 2dc61013be
12 changed files with 182 additions and 324 deletions

View File

@ -6,7 +6,6 @@ use crate::{Error, Result};
use pest::iterators::Pair;
use pest::Parser;
use std::collections::BTreeMap;
use std::num::{ParseFloatError, ParseIntError};
#[derive(Parser)]
#[grammar = "query.pest"]
@ -242,24 +241,17 @@ fn parse_value2(pair: Pair<Rule>, pc: &mut PositionCalculator) -> Result<Value>
Rule::object => parse_object_value(pair, pc)?,
Rule::array => parse_array_value(pair, pc)?,
Rule::variable => Value::Variable(parse_variable(pair, pc)?.into_inner()),
Rule::float => {
Rule::float | Rule::int => {
let pos = pc.step(&pair);
Value::Float(
Value::Number(
pair.as_str()
.parse()
.map_err(|err: ParseFloatError| Error {
.map_err(|err: serde_json::Error| Error {
pos,
message: err.to_string(),
})?,
)
}
Rule::int => {
let pos = pc.step(&pair);
Value::Int(pair.as_str().parse().map_err(|err: ParseIntError| Error {
pos,
message: err.to_string(),
})?)
}
Rule::string => Value::String({
let pos = pc.step(&pair);
unquote_string(pair.as_str(), pos)?
@ -531,18 +523,8 @@ mod tests {
#[test]
fn test_parse_overflowing_int() {
let query_ok = format!("mutation {{ add(big: {}) }} ", std::i32::MAX);
let query_overflow = format!("mutation {{ add(big: {}0) }} ", std::i32::MAX);
let query_overflow = format!("mutation {{ add(big: {}0000) }} ", std::i32::MAX);
assert!(parse_query(query_ok).is_ok());
assert!(parse_query(query_overflow).is_err());
}
#[test]
fn test_parse_overflowing_float() {
let query_ok = format!("mutation {{ add(big: {:.1}) }} ", std::f64::MAX);
let query_overflow = format!("mutation {{ add(big: 1{:.1}) }} ", std::f64::MAX);
assert!(parse_query(query_ok).is_ok());
// NOTE: This is also ok since overflow gets parsed to infinity.
assert!(parse_query(query_overflow).is_ok());
}
}

View File

@ -33,8 +33,7 @@ impl Clone for UploadValue {
pub enum Value {
Null,
Variable(String),
Int(i32),
Float(f64),
Number(serde_json::Number),
String(String),
Boolean(bool),
Enum(String),
@ -51,8 +50,7 @@ impl serde::Serialize for Value {
match self {
Value::Null => serializer.serialize_none(),
Value::Variable(variable) => serializer.serialize_str(&format!("${}", variable)),
Value::Int(value) => serializer.serialize_i32(*value),
Value::Float(value) => serializer.serialize_f64(*value),
Value::Number(value) => value.serialize(serializer),
Value::String(value) => serializer.serialize_str(value),
Value::Boolean(value) => serializer.serialize_bool(*value),
Value::Enum(value) => serializer.serialize_str(value),
@ -87,8 +85,7 @@ impl PartialEq for Value {
match (self, other) {
(Variable(a), Variable(b)) => a.eq(b),
(Int(a), Int(b)) => a.eq(b),
(Float(a), Float(b)) => a.eq(b),
(Number(a), Number(b)) => a.eq(b),
(String(a), String(b)) => a.eq(b),
(Boolean(a), Boolean(b)) => a.eq(b),
(Null, Null) => true,
@ -145,8 +142,7 @@ impl fmt::Display for Value {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
match self {
Value::Variable(name) => write!(f, "${}", name),
Value::Int(num) => write!(f, "{}", *num),
Value::Float(val) => write!(f, "{}", *val),
Value::Number(num) => write!(f, "{}", *num),
Value::String(ref val) => write_quoted(val, f),
Value::Boolean(true) => write!(f, "true"),
Value::Boolean(false) => write!(f, "false"),
@ -188,8 +184,7 @@ impl From<Value> for serde_json::Value {
match value {
Value::Null => serde_json::Value::Null,
Value::Variable(name) => name.into(),
Value::Int(n) => n.into(),
Value::Float(n) => n.into(),
Value::Number(n) => serde_json::Value::Number(n),
Value::String(s) => s.into(),
Value::Boolean(v) => v.into(),
Value::Enum(e) => e.into(),
@ -213,8 +208,7 @@ impl From<serde_json::Value> for Value {
match value {
serde_json::Value::Null => Value::Null,
serde_json::Value::Bool(n) => Value::Boolean(n),
serde_json::Value::Number(n) if n.is_f64() => Value::Float(n.as_f64().unwrap()),
serde_json::Value::Number(n) => Value::Int(n.as_i64().unwrap() as i32),
serde_json::Value::Number(n) => Value::Number(n),
serde_json::Value::String(s) => Value::String(s),
serde_json::Value::Array(ls) => Value::List(ls.into_iter().map(Into::into).collect()),
serde_json::Value::Object(obj) => Value::Object(

View File

@ -15,12 +15,12 @@ struct StringNumber(i64);
#[Scalar]
impl ScalarType for StringNumber {
fn parse(value: Value) -> InputValueResult<Self> {
if let Value::String(value) = value {
if let Value::String(value) = &value {
// Parse the integer value
value.parse().map(StringNumber)?
Ok(value.parse().map(StringNumber)?)
} else {
// If the type does not match
InputValueError::ExpectedType
Err(InputValueError::ExpectedType(value))
}
}

View File

@ -15,12 +15,12 @@ struct StringNumber(i64);
#[Scalar]
impl ScalarType for StringNumber {
fn parse(value: Value) -> InputValueResult<Self> {
if let Value::String(value) = value {
if let Value::String(value) = &value {
// 解析整数
value.parse().map(StringNumber)?
Ok(value.parse().map(StringNumber)?)
} else {
// 类型不匹配
InputValueError::ExpectedType
Err(InputValueError::ExpectedType(value))
}
}

View File

@ -116,15 +116,16 @@ pub trait InputObjectType: InputValueType {}
/// #[Scalar]
/// impl ScalarType for MyInt {
/// fn parse(value: Value) -> InputValueResult<Self> {
/// if let Value::Int(n) = value {
/// Ok(MyInt(n as i32))
/// } else {
/// Err(InputValueError::ExpectedType(value))
/// if let Value::Number(n) = &value {
/// if let Some(n) = n.as_i64() {
/// return Ok(MyInt(n as i32));
/// }
/// }
/// Err(InputValueError::ExpectedType(value))
/// }
///
/// fn to_value(&self) -> Value {
/// Value::Int(self.0)
/// Value::Number(self.0.into())
/// }
/// }
/// ```

View File

@ -46,7 +46,11 @@ mod test {
#[test]
fn test_conversion_ok() {
let value = Value::List(vec![Value::Int(1.into()), Value::Float(2.0), Value::Null]);
let value = Value::List(vec![
Value::Number(1.into()),
Value::Boolean(true),
Value::Null,
]);
let expected = Any(value.clone());
let output: Any = value.into();
assert_eq!(output, expected);

View File

@ -1,48 +1,35 @@
use crate::{InputValueError, InputValueResult, ScalarType, Value};
use async_graphql_derive::Scalar;
/// The `Float` scalar type represents signed double-precision fractional values as specified by [IEEE 754](https://en.wikipedia.org/wiki/IEEE_floating_point).
#[Scalar(internal, name = "Float")]
impl ScalarType for f32 {
fn parse(value: Value) -> InputValueResult<Self> {
match value {
Value::Int(n) => Ok(n as Self),
Value::Float(n) => Ok(n as Self),
_ => Err(InputValueError::ExpectedType(value)),
}
}
macro_rules! float_scalar {
($($ty:ty),*) => {
$(
/// The `Float` scalar type represents signed double-precision fractional values as specified by [IEEE 754](https://en.wikipedia.org/wiki/IEEE_floating_point).
#[Scalar(internal, name = "Float")]
impl ScalarType for $ty {
fn parse(value: Value) -> InputValueResult<Self> {
match value {
Value::Number(n) => Ok(n
.as_f64()
.ok_or_else(|| InputValueError::from("Invalid number"))?
as Self),
_ => Err(InputValueError::ExpectedType(value)),
}
}
fn is_valid(value: &Value) -> bool {
match value {
Value::Int(_) | Value::Float(_) => true,
_ => false,
}
}
fn is_valid(value: &Value) -> bool {
match value {
Value::Number(_) => true,
_ => false,
}
}
fn to_value(&self) -> Value {
Value::Float(*self as f64)
fn to_value(&self) -> Value {
Value::Number(serde_json::Number::from_f64(*self as f64).unwrap())
}
}
)*
}
}
/// The `Float` scalar type represents signed double-precision fractional values as specified by [IEEE 754](https://en.wikipedia.org/wiki/IEEE_floating_point).
#[Scalar(internal, name = "Float")]
impl ScalarType for f64 {
fn parse(value: Value) -> InputValueResult<Self> {
match value {
Value::Int(n) => Ok(n as Self),
Value::Float(n) => Ok(n as Self),
_ => Err(InputValueError::ExpectedType(value)),
}
}
fn is_valid(value: &Value) -> bool {
match value {
Value::Int(_) | Value::Float(_) => true,
_ => false,
}
}
fn to_value(&self) -> Value {
Value::Float(*self as f64)
}
}
float_scalar!(f32, f64);

View File

@ -77,7 +77,7 @@ impl PartialEq<&str> for ID {
impl ScalarType for ID {
fn parse(value: Value) -> InputValueResult<Self> {
match value {
Value::Int(n) => Ok(ID(n.to_string())),
Value::Number(n) if n.is_i64() => Ok(ID(n.to_string())),
Value::String(s) => Ok(ID(s)),
_ => Err(InputValueError::ExpectedType(value)),
}
@ -85,7 +85,8 @@ impl ScalarType for ID {
fn is_valid(value: &Value) -> bool {
match value {
Value::Int(_) | Value::String(_) => true,
Value::Number(n) if n.is_i64() => true,
Value::String(_) => true,
_ => false,
}
}

View File

@ -1,191 +1,85 @@
use crate::{InputValueError, InputValueResult, ScalarType, Value};
use async_graphql_derive::Scalar;
/// The `Int` scalar type represents non-fractional signed whole numeric values. Int can represent values between -(2^31) and 2^31 - 1.
#[Scalar(internal, name = "Int")]
impl ScalarType for i8 {
fn parse(value: Value) -> InputValueResult<Self> {
match value {
Value::Int(n) => Ok(n as Self),
_ => Err(InputValueError::ExpectedType(value)),
}
}
fn is_valid(value: &Value) -> bool {
match value {
Value::Int(_) => true,
_ => false,
}
}
fn to_value(&self) -> Value {
Value::Int(*self as i32)
}
}
/// The `Int` scalar type represents non-fractional signed whole numeric values. Int can represent values between -(2^31) and 2^31 - 1.
#[Scalar(internal, name = "Int")]
impl ScalarType for i16 {
fn parse(value: Value) -> InputValueResult<Self> {
match value {
Value::Int(n) => Ok(n as Self),
_ => Err(InputValueError::ExpectedType(value)),
}
}
fn is_valid(value: &Value) -> bool {
match value {
Value::Int(_) => true,
_ => false,
}
}
fn to_value(&self) -> Value {
Value::Int(*self as i32)
}
}
/// The `Int` scalar type represents non-fractional signed whole numeric values. Int can represent values between -(2^31) and 2^31 - 1.
#[Scalar(internal, name = "Int")]
impl ScalarType for i32 {
fn parse(value: Value) -> InputValueResult<Self> {
match value {
Value::Int(n) => Ok(n as Self),
_ => Err(InputValueError::ExpectedType(value)),
}
}
fn is_valid(value: &Value) -> bool {
match value {
Value::Int(_) => true,
_ => false,
}
}
fn to_value(&self) -> Value {
Value::Int(*self as i32)
}
}
/// The `Int` scalar type represents non-fractional signed whole numeric values. Int can represent values between -(2^31) and 2^31 - 1.
#[Scalar(internal, name = "Int")]
impl ScalarType for u8 {
fn parse(value: Value) -> InputValueResult<Self> {
match value {
Value::Int(n) => Ok(n as Self),
_ => Err(InputValueError::ExpectedType(value)),
}
}
fn is_valid(value: &Value) -> bool {
match value {
Value::Int(_) => true,
_ => false,
}
}
fn to_value(&self) -> Value {
Value::Int(*self as i32)
}
}
/// The `Int` scalar type represents non-fractional signed whole numeric values. Int can represent values between -(2^31) and 2^31 - 1.
#[Scalar(internal, name = "Int")]
impl ScalarType for u16 {
fn parse(value: Value) -> InputValueResult<Self> {
match value {
Value::Int(n) => Ok(n as Self),
_ => Err(InputValueError::ExpectedType(value)),
}
}
fn is_valid(value: &Value) -> bool {
match value {
Value::Int(_) => true,
_ => false,
}
}
fn to_value(&self) -> Value {
Value::Int(*self as i32)
}
}
/// The `Int64` scalar type represents non-fractional signed whole numeric values. Int can represent values between -(2^64) and 2^64 - 1.
#[Scalar(internal, name = "Int64")]
impl ScalarType for i64 {
fn parse(value: Value) -> InputValueResult<Self> {
match value {
Value::Int(n) => Ok(n as Self),
Value::String(s) => Ok(s.parse()?),
_ => Err(InputValueError::ExpectedType(value)),
}
}
fn is_valid(value: &Value) -> bool {
match value {
Value::Int(_) | Value::String(_) => true,
_ => false,
}
}
fn to_value(&self) -> Value {
Value::String(self.to_string())
}
}
/// The `UInt64` scalar type represents non-fractional signed whole numeric values. Int can represent values between 0 and 2^64.
#[Scalar(internal, name = "UInt64")]
impl ScalarType for u32 {
fn parse(value: Value) -> InputValueResult<Self> {
match value {
Value::Int(n) => {
if n < 0 {
return Err(InputValueError::Custom("Expect a positive number.".into()));
macro_rules! int_scalar {
($($ty:ty),*) => {
$(
/// The `Int` scalar type represents non-fractional whole numeric values.
#[Scalar(internal, name = "Int")]
impl ScalarType for $ty {
fn parse(value: Value) -> InputValueResult<Self> {
match value {
Value::Number(n) => {
let n = n
.as_i64()
.ok_or_else(|| InputValueError::from("Invalid number"))?;
if n < Self::MIN as i64 || n > Self::MAX as i64 {
return Err(InputValueError::from(format!(
"Only integers from {} to {} are accepted.",
Self::MIN,
Self::MAX
)));
}
Ok(n as Self)
}
_ => Err(InputValueError::ExpectedType(value)),
}
Ok(n as Self)
}
Value::String(s) => Ok(s.parse()?),
_ => Err(InputValueError::ExpectedType(value)),
}
}
fn is_valid(value: &Value) -> bool {
match value {
Value::Int(_) | Value::String(_) => true,
_ => false,
}
}
fn to_value(&self) -> Value {
Value::String(self.to_string())
}
}
/// The `UInt64` scalar type represents non-fractional signed whole numeric values. Int can represent values between 0 and 2^64.
#[Scalar(internal, name = "UInt64")]
impl ScalarType for u64 {
fn parse(value: Value) -> InputValueResult<Self> {
match value {
Value::Int(n) => {
if n < 0 {
return Err(InputValueError::Custom("Expect a positive number.".into()));
fn is_valid(value: &Value) -> bool {
match value {
Value::Number(n) if n.is_i64() => true,
_ => false,
}
Ok(n as Self)
}
Value::String(s) => Ok(s.parse()?),
_ => Err(InputValueError::ExpectedType(value)),
}
}
fn is_valid(value: &Value) -> bool {
match value {
Value::Int(_) | Value::String(_) => true,
_ => false,
fn to_value(&self) -> Value {
Value::Number(serde_json::Number::from(*self as i64))
}
}
}
fn to_value(&self) -> Value {
Value::String(self.to_string())
}
)*
};
}
macro_rules! uint_scalar {
($($ty:ty),*) => {
$(
/// The `Int` scalar type represents non-fractional whole numeric values.
#[Scalar(internal, name = "Int")]
impl ScalarType for $ty {
fn parse(value: Value) -> InputValueResult<Self> {
match value {
Value::Number(n) => {
let n = n
.as_u64()
.ok_or_else(|| InputValueError::from("Invalid number"))?;
if n > Self::MAX as u64 {
return Err(InputValueError::from(format!(
"Only integers from {} to {} are accepted.",
0,
Self::MAX
)));
}
Ok(n as Self)
}
_ => Err(InputValueError::ExpectedType(value)),
}
}
fn is_valid(value: &Value) -> bool {
match value {
Value::Number(n) if n.is_u64() => true,
_ => false,
}
}
fn to_value(&self) -> Value {
Value::Number(serde_json::Number::from(*self as u64))
}
}
)*
};
}
int_scalar!(i8, i16, i32, i64);
uint_scalar!(u8, u16, u32, u64);

View File

@ -4,72 +4,69 @@ use crate::Value;
/// Integer range validator
pub struct IntRange {
/// Minimum value, including this value.
pub min: i32,
pub min: i64,
/// Maximum value, including this value.
pub max: i32,
pub max: i64,
}
impl InputValueValidator for IntRange {
fn is_valid(&self, value: &Value) -> Option<String> {
if let Value::Int(n) = value {
if *n < self.min || *n > self.max {
Some(format!(
"the value is {}, must be between {} and {}",
*n, self.min, self.max
))
} else {
None
if let Value::Number(n) = value {
if let Some(n) = n.as_i64() {
if n < self.min || n > self.max {
return Some(format!(
"the value is {}, must be between {} and {}",
n, self.min, self.max
));
}
}
} else {
None
}
None
}
}
/// Integer less then validator
pub struct IntLessThan {
/// Less then this value.
pub value: i32,
pub value: i64,
}
impl InputValueValidator for IntLessThan {
fn is_valid(&self, value: &Value) -> Option<String> {
if let Value::Int(n) = value {
if *n >= self.value {
Some(format!(
"the value is {}, must be less than {}",
*n, self.value
))
} else {
None
if let Value::Number(n) = value {
if let Some(n) = n.as_i64() {
if n >= self.value {
return Some(format!(
"the value is {}, must be less than {}",
n, self.value
));
}
}
} else {
None
}
None
}
}
/// Integer greater then validator
pub struct IntGreaterThan {
/// Greater then this value.
pub value: i32,
pub value: i64,
}
impl InputValueValidator for IntGreaterThan {
fn is_valid(&self, value: &Value) -> Option<String> {
if let Value::Int(n) = value {
if *n <= self.value {
Some(format!(
"the value is {}, must be greater than {}",
*n, self.value
))
} else {
None
if let Value::Number(n) = value {
if let Some(n) = n.as_i64() {
if n <= self.value {
return Some(format!(
"the value is {}, must be greater than {}",
n, self.value
));
}
}
} else {
None
}
None
}
}
@ -78,37 +75,35 @@ pub struct IntNonZero {}
impl InputValueValidator for IntNonZero {
fn is_valid(&self, value: &Value) -> Option<String> {
if let Value::Int(n) = value {
if *n == 0 {
Some(format!("the value is {}, must be nonzero", *n,))
} else {
None
if let Value::Number(n) = value {
if let Some(n) = n.as_i64() {
if n == 0 {
return Some(format!("the value is {}, must be nonzero", n));
}
}
} else {
None
}
None
}
}
/// Integer equal validator
pub struct IntEqual {
/// equal this value.
pub value: i32,
pub value: i64,
}
impl InputValueValidator for IntEqual {
fn is_valid(&self, value: &Value) -> Option<String> {
if let Value::Int(n) = value {
if *n != self.value {
Some(format!(
"the value is {}, must be equal to {}",
*n, self.value
))
} else {
None
if let Value::Number(n) = value {
if let Some(n) = n.as_i64() {
if n != self.value {
return Some(format!(
"the value is {}, must be equal to {}",
n, self.value
));
}
}
} else {
None
}
None
}
}

View File

@ -6,13 +6,13 @@ pub async fn test_input_value_custom_error() {
#[Object]
impl Query {
async fn parse_int(&self, _n: i64) -> bool {
async fn parse_int(&self, _n: i8) -> bool {
true
}
}
let schema = Schema::new(Query, EmptyMutation, EmptySubscription);
let query = r#"{ parseInt(n:"A") }"#;
let query = r#"{ parseInt(n:289) }"#;
assert_eq!(
schema.execute(&query).await.unwrap_err(),
Error::Query {
@ -22,7 +22,7 @@ pub async fn test_input_value_custom_error() {
},
path: None,
err: QueryError::ParseInputValue {
reason: "invalid digit found in string".to_string()
reason: "Only integers from -128 to 127 are accepted.".to_string()
},
}
);

View File

@ -84,7 +84,7 @@ impl ScalarType for TestScalar {
}
fn to_value(&self) -> Value {
Value::Int(self.0.clone())
Value::Number(self.0.into())
}
}