Skip to content

Support scalar specification URL #27

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
9 changes: 9 additions & 0 deletions graphql/introspection.lua
Original file line number Diff line number Diff line change
Expand Up @@ -347,6 +347,15 @@ __Type = types.object({
end,
},

specifiedByUrl = {
kind = types.string,
resolve = function(kind)
if kind.__type == 'Scalar' then
return kind.specifiedByUrl
end
end,
},

ofType = {
kind = __Type,
},
Expand Down
1 change: 1 addition & 0 deletions graphql/schema.lua
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@ function schema.create(config, name)
self.directives = self.directives or {
types.include,
types.skip,
types.specifiedBy,
}

self.typeMap = {}
Expand Down
10 changes: 10 additions & 0 deletions graphql/types.lua
Original file line number Diff line number Diff line change
Expand Up @@ -97,6 +97,7 @@ function types.scalar(config)
parseValue = config.parseValue,
parseLiteral = config.parseLiteral,
isValueOfTheType = config.isValueOfTheType,
specifiedByUrl = config.specifiedByUrl,
}

instance.nonNull = types.nonNull(instance)
Expand Down Expand Up @@ -459,6 +460,15 @@ types.skip = types.directive({
onInlineFragment = true,
})

types.specifiedBy = types.directive({
name = 'specifiedBy',
description = 'Custom scalar specification.',
arguments = {
['url'] = { kind = types.string.nonNull, description = 'Scalar specification URL.', }
},
onScalar = true,
})

types.resolve = function(type_name_or_obj, schema)
if type(type_name_or_obj) == 'table' then
return type_name_or_obj
Expand Down
8 changes: 8 additions & 0 deletions graphql/util.lua
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,13 @@ local function find(t, fn)
end
end

local function find_by_name(t, name)
for _, v in pairs(t or {}) do
if v.name == name then return v end
end
return nil
end

local function filter(t, fn)
local res = {}
for _,v in pairs(t) do
Expand Down Expand Up @@ -282,6 +289,7 @@ return {
map = map,
map_name = map_name,
find = find,
find_by_name = find_by_name,
filter = filter,
values = values,
compose = compose,
Expand Down
84 changes: 84 additions & 0 deletions test/integration/graphql_test.lua
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ local schema = require('graphql.schema')
local parse = require('graphql.parse')
local validate = require('graphql.validate')
local execute = require('graphql.execute')
local util = require('graphql.util')
local introspection = require('test.integration.introspection')

local t = require('luatest')
Expand Down Expand Up @@ -1425,3 +1426,86 @@ function g.test_custom_directives()
t.assert_equals(data, { test_G = '{"num":5,"str":"news"}' })
t.assert_equals(errors, nil)
end

function g.test_specifiedByUrl_scalar_field()
local function callback(_, _)
return nil
end

local custom_scalar = types.scalar({
name = 'CustomInt',
description = "The `CustomInt` scalar type represents non-fractional signed whole numeric values. " ..
"Int can represent values from -(2^31) to 2^31 - 1, inclusive.",
serialize = function(value)
return value
end,
parseLiteral = function(node)
return node.value
end,
isValueOfTheType = function(_)
return true
end,
specifiedByUrl = 'http://localhost',
})

local query_schema = {
['test'] = {
kind = types.string.nonNull,
arguments = {
arg = custom_scalar,
},
resolve = callback,
}
}

local data, errors = check_request(introspection.query, query_schema)
local CustomInt_schema = util.find_by_name(data.__schema.types, 'CustomInt')
t.assert_type(CustomInt_schema, 'table', 'CustomInt schema found on introspection')
t.assert_equals(CustomInt_schema.specifiedByUrl, 'http://localhost')
t.assert_equals(errors, nil)
end

function g.test_specifiedBy_directive()
local function callback(_, args, info)
local v = args[1].value
local dir = info.directives
if dir ~= nil and dir.specifiedBy ~= nil then
return { value = v, url = dir.specifiedBy.url }
end

return { value = v }
end

local custom_scalar = types.scalar({
name = 'CustomInt',
description = "The `CustomInt` scalar type represents non-fractional signed whole numeric values. " ..
"Int can represent values from -(2^31) to 2^31 - 1, inclusive.",
serialize = function(value)
return value
end,
parseLiteral = function(node)
return node.value
end,
isValueOfTheType = function(_)
return true
end,
})

local query_schema = {
['test'] = {
kind = custom_scalar,
arguments = {
arg = custom_scalar,
},
resolve = callback,
}
}

local query = [[query {
test_A: test(arg: 1)@specifiedBy(url: "http://localhost")
}]]

local data, errors = check_request(query, query_schema)
t.assert_equals(data, { test_A = { url = "http://localhost", value = "1" } })
t.assert_equals(errors, nil)
end
19 changes: 19 additions & 0 deletions test/unit/graphql_test.lua
Original file line number Diff line number Diff line change
Expand Up @@ -1069,3 +1069,22 @@ function g.test_util_map_name()
res = util.map_name({ entry_a = { name = 'a' }, entry_b = { name = 'b' }, }, function(v) return v end)
t.assert_equals(res, {a = {name = 'a'}, b = {name = 'b'}})
end

function g.test_util_find_by_name()
local res = util.find_by_name({}, 'var')
t.assert_equals(res, nil)

res = util.find_by_name({ { name = 'avr' } }, 'var')
t.assert_equals(res, nil)

res = util.find_by_name({ { name = 'avr', value = 1 }, { name = 'var', value = 2 } }, 'var')
t.assert_equals(res, { name = 'var', value = 2 })

res = util.find_by_name(
{
entry1 = { name = 'avr', value = 1 },
entry2 = { name = 'var', value = 2 }
},
'var')
t.assert_equals(res, { name = 'var', value = 2 })
end