diff --git a/core/src/main/scala/caliban/interop/jsoniter/jsoniter.scala b/core/src/main/scala/caliban/interop/jsoniter/jsoniter.scala index f154271e1..e2d5cd13b 100644 --- a/core/src/main/scala/caliban/interop/jsoniter/jsoniter.scala +++ b/core/src/main/scala/caliban/interop/jsoniter/jsoniter.scala @@ -123,7 +123,7 @@ private[caliban] object ValueJsoniter { StringValue(in.readString(null)) case x if x == '-' || (x >= '0' && x <= '9') => in.rollbackToken() - numberParser(in) + parseNumber(in) case 'n' => in.readNullOrError(NullValue, "unexpected JSON value") case 'f' | 't' => @@ -169,7 +169,7 @@ private[caliban] object ValueJsoniter { StringValue(in.readString(null)) case x if x == '-' || (x >= '0' && x <= '9') => in.rollbackToken() - numberParser(in) + parseNumber(in) case 'n' => in.readNullOrError(NullValue, "unexpected JSON value") case 'f' | 't' => @@ -203,32 +203,19 @@ private[caliban] object ValueJsoniter { in.decodeError(s"unexpected token $c") } - private val numberParser: JsonReader => Value = in => { - in.setMark() - var digits = 0 - var b = in.nextByte() - if (b == '-') b = in.nextByte() - try - while (b >= '0' && b <= '9') { - digits += 1 - b = in.nextByte() - } - catch { - case _: JsonReaderException => // ignore the end of input error for now + private def parseNumber(in: JsonReader): Value = + in.readNumber(null) match { + case l: java.lang.Long => + val asLong = l.longValue() + val asInt = asLong.toInt + // Check if the number can fit in an Int (most common case) + if (asInt.toLong == asLong) Value.IntValue.IntNumber(asInt) + else Value.IntValue.LongNumber(asLong) + case bd: java.math.BigDecimal => + Value.FloatValue.BigDecimalNumber(bd) + case bi: java.math.BigInteger => + Value.IntValue.BigIntNumber(bi) } - in.rollbackToMark() - - if ((b | 0x20) != 'e' && b != '.') { - if (digits < 19) { - if (digits < 10) Value.IntValue.IntNumber(in.readInt()) - else Value.IntValue.LongNumber(in.readLong()) - } else { - val x = in.readBigInt(null) - if (x.bitLength < 64) Value.IntValue.LongNumber(x.longValue) - else Value.IntValue.BigIntNumber(x.bigInteger) - } - } else Value.FloatValue.BigDecimalNumber(in.readBigDecimal(null).bigDecimal) - } val inputValueCodec: JsonValueCodec[InputValue] = new JsonValueCodec[InputValue] { override def decodeValue(in: JsonReader, default: InputValue): InputValue = diff --git a/core/src/test/scala/caliban/interop/jsoniter/GraphQLRequestJsoniterSpec.scala b/core/src/test/scala/caliban/interop/jsoniter/GraphQLRequestJsoniterSpec.scala index 9a769ecc3..c498ba39b 100644 --- a/core/src/test/scala/caliban/interop/jsoniter/GraphQLRequestJsoniterSpec.scala +++ b/core/src/test/scala/caliban/interop/jsoniter/GraphQLRequestJsoniterSpec.scala @@ -11,7 +11,7 @@ object GraphQLRequestJsoniterSpec extends ZIOSpecDefault { suite("GraphQLRequestJsoniterSpec")( test("can be parsed from JSON by jsoniter") { val request = - """{"query": "{}", "operationName": "op", "variables": {"hello":"world","answer":42,"isAwesome":true, "name": null}}""" + """{"query": "{}", "operationName": "op", "variables": {"hello":"world","intValue":42,"longValue":99999999999,"bigIntValue":9223372036854775810,"decimalValue":1.1,"bigDecimalValue":4.4028235E38,"isAwesome":true, "name": null}}""" assert(readFromString[GraphQLRequest](request))( equalTo( GraphQLRequest( @@ -19,10 +19,14 @@ object GraphQLRequestJsoniterSpec extends ZIOSpecDefault { operationName = Some("op"), variables = Some( Map( - "hello" -> Value.StringValue("world"), - "answer" -> Value.IntValue(42), - "isAwesome" -> Value.BooleanValue(true), - "name" -> Value.NullValue + "hello" -> Value.StringValue("world"), + "intValue" -> Value.IntValue.IntNumber(42), + "longValue" -> Value.IntValue.LongNumber(99999999999L), + "bigIntValue" -> Value.IntValue.BigIntNumber(BigInt("9223372036854775810")), + "decimalValue" -> Value.FloatValue(BigDecimal("1.1")), + "bigDecimalValue" -> Value.FloatValue(BigDecimal("4.4028235E38")), + "isAwesome" -> Value.BooleanValue(true), + "name" -> Value.NullValue ) ) )