From ba60c6c113e660585796d3cde1f0cc0fcf40b30b Mon Sep 17 00:00:00 2001 From: Brandon Buck Date: Mon, 9 Nov 2015 10:21:39 -0600 Subject: [PATCH] fix integer coercion. --- scalars.go | 48 ++++++++++++++++++++++++++--------- scalars_serialization_test.go | 25 +++++++++--------- 2 files changed, 49 insertions(+), 24 deletions(-) diff --git a/scalars.go b/scalars.go index 78505db6..4611ccdb 100644 --- a/scalars.go +++ b/scalars.go @@ -2,29 +2,52 @@ package graphql import ( "fmt" + "math" "strconv" "github.com/graphql-go/graphql/language/ast" ) -var ( - MaxInt = 9007199254740991 - MinInt = -9007199254740991 +const ( + MaxInt int64 = 9007199254740991 + MinInt int64 = -9007199254740991 ) func coerceInt(value interface{}) interface{} { switch value := value.(type) { case bool: if value == true { - return int(1) + return int64(1) } - return int(0) + return int64(0) case int: - return value + return int64(value) + case int8: + return int64(value) + case int16: + return int64(value) + case int32: + return int64(value) + case int64: + return intOrNil(value) + case uint: + return int64(value) + case uint8: + return int64(value) + case uint16: + return int64(value) + case uint32: + return int64(value) + case uint64: + if value > uint64(math.MaxInt64) { + // bypass intOrNil + return nil + } + return intOrNil(int64(value)) case float32: - return intOrNil(int(value)) + return intOrNil(int64(value)) case float64: - return intOrNil(int(value)) + return intOrNil(int64(value)) case string: val, err := strconv.ParseFloat(value, 0) if err != nil { @@ -32,14 +55,15 @@ func coerceInt(value interface{}) interface{} { } return coerceInt(val) } - return int(0) + + return nil } // Integers are only safe when between -(2^53 - 1) and 2^53 - 1 due to being // encoded in JavaScript and represented in JSON as double-precision floating // point numbers, as specified by IEEE 754. -func intOrNil(value int) interface{} { - if value <= MaxInt && value >= MinInt { +func intOrNil(value int64) interface{} { + if MinInt <= value && value <= MaxInt { return value } return nil @@ -52,7 +76,7 @@ var Int *Scalar = NewScalar(ScalarConfig{ ParseLiteral: func(valueAST ast.Value) interface{} { switch valueAST := valueAST.(type) { case *ast.IntValue: - if intValue, err := strconv.Atoi(valueAST.Value); err == nil { + if intValue, err := strconv.ParseInt(valueAST.Value, 10, 64); err == nil { return intValue } } diff --git a/scalars_serialization_test.go b/scalars_serialization_test.go index ac4a990b..c6b84e3b 100644 --- a/scalars_serialization_test.go +++ b/scalars_serialization_test.go @@ -28,21 +28,22 @@ type boolSerializationTest struct { func TestTypeSystem_Scalar_SerializesOutputInt(t *testing.T) { tests := []intSerializationTest{ - {1, 1}, - {0, 0}, - {-1, -1}, - {float32(0.1), 0}, - {float32(1.1), 1}, - {float32(-1.1), -1}, - {float32(1e5), 100000}, // Bigger than 2^32, but still representable as an Int - {9876504321, 9876504321}, - {-9876504321, -9876504321}, + {1, int64(1)}, + {0, int64(0)}, + {-1, int64(-1)}, + {float32(0.1), int64(0)}, + {float32(1.1), int64(1)}, + {float32(-1.1), int64(-1)}, + // Bigger than 2^32, but still representable as an Int + {float32(1e5), int64(100000)}, + {9876504321, int64(9876504321)}, + {-9876504321, int64(-9876504321)}, {float64(1e100), nil}, {float64(-1e100), nil}, - {"-1.1", -1}, + {"-1.1", int64(-1)}, {"one", nil}, - {false, 0}, - {true, 1}, + {false, int64(0)}, + {true, int64(1)}, } for _, test := range tests {