diff --git a/graphql/types.lua b/graphql/types.lua index 8b21282..93e939e 100644 --- a/graphql/types.lua +++ b/graphql/types.lua @@ -318,7 +318,24 @@ types.long = types.scalar({ }) local function isFloat(value) - return type(value) == 'number' + -- According to http://spec.graphql.org/October2021/#sec-Float + -- Non-finite floating-point internal values (NaN and Infinity) + -- cannot be coerced to Float and must raise a field error. + if type(value) == 'number' then + if value == value and value ~= tonumber('Inf') and value ~= tonumber('-Inf') then + return true + else + return false + end + end + + if ffi.istype('int64_t', value) then + return value >= -2^53 and value < 2^53 + elseif ffi.istype('uint64_t', value) then + return value < 2^53 + end + + return false end local function coerceFloat(value) diff --git a/test/integration/graphql_test.lua b/test/integration/graphql_test.lua index be7d57e..cb2c0b7 100644 --- a/test/integration/graphql_test.lua +++ b/test/integration/graphql_test.lua @@ -2051,3 +2051,83 @@ g.test_propagate_defaults_to_callback = function() t.assert_equals(errors, nil) t.assert_items_equals(json.decode(data.prefix.test_mutation), result) end + +function g.test_float_variables() + local query_variable = [[ + query ($arg: Float) { test(arg: $arg) } + ]] + + local floats_positive = { + '9007199254740991', + '-9007199254740992', + '0', + '9007199254740991.1', + '-9007199254740992.1', + '99999999999999', + '100000000000000', + '-99999999999999', + '-100000000000000', + '1e1', + '-1e1', + } + + local floats_negative = { + '9007199254740992', + '-9007199254740993', + 'nan', + 'inf', + '-inf', + } + + local function callback(_, args) + return args[1].value + end + + local query_schema = { + ['test'] = { + kind = types.float, + arguments = { + arg = types.float, + }, + resolve = callback, + } + } + + local query_argument = function(value) + return '{ test(arg: '..value..' ) }' + end + + -- Positive tests + for _, value in ipairs(floats_positive) do + t.assert_items_equals( + check_request( + query_variable, + query_schema, + nil, + nil, + {variables = json.decode('{"arg": '.. value .. '}')} + ), + {test = tonumber(value)} + ) + t.assert_items_equals( + check_request(query_argument(value), query_schema), + {test = tonumber(value)} + ) + end + + -- Negative tests + for _, value in ipairs(floats_negative) do + t.assert_error_msg_equals( + 'Wrong variable \"arg\" for the Scalar \"Float\"', + function() + check_request( + query_variable, + query_schema, + nil, + nil, + {variables = json.decode('{"arg": '.. value .. '}')} + ) + end + ) + end +end