Skip to content
This repository was archived by the owner on Apr 14, 2022. It is now read-only.

Fix selection existence validation #177

Merged
merged 1 commit into from
Jun 18, 2018
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
26 changes: 0 additions & 26 deletions graphql/convert_schema/core_types_helpers.lua

This file was deleted.

11 changes: 5 additions & 6 deletions graphql/convert_schema/resolve.lua
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@

local json = require('json')
local yaml = require('yaml')
local core_types_helpers = require('graphql.convert_schema.core_types_helpers')
local core_types = require('graphql.core.types')

local utils = require('graphql.utils')
local check = utils.check
Expand Down Expand Up @@ -86,17 +86,16 @@ end
function resolve.gen_resolve_function(collection_name, connection,
destination_type, arguments, accessor)
local c = connection
local raw_destination_type = core_types_helpers.raw_gql_type(
destination_type)
local bare_destination_type = core_types.bare(destination_type)

-- capture `raw_destination_type`
-- capture `bare_destination_type`
local function genResolveField(info)
return function(field_name, object, filter, opts)
assert(raw_destination_type.fields[field_name],
assert(bare_destination_type.fields[field_name],
('performing a subrequest by the non-existent ' ..
'field "%s" of the collection "%s"'):format(field_name,
c.destination_collection))
return raw_destination_type.fields[field_name].resolve(
return bare_destination_type.fields[field_name].resolve(
object, filter, info, opts)
end
end
Expand Down
7 changes: 3 additions & 4 deletions graphql/convert_schema/schema.lua
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,6 @@

local core_types = require('graphql.core.types')
local core_schema = require('graphql.core.schema')
local core_types_helpers = require('graphql.convert_schema.core_types_helpers')
local gen_arguments = require('graphql.gen_arguments')
local arguments = require('graphql.convert_schema.arguments')
local types = require('graphql.convert_schema.types')
Expand Down Expand Up @@ -64,7 +63,7 @@ local function add_extra_arguments(state, root_types)
-- XXX: support multihead connections
if c.destination_collection then
local collection_name = c.destination_collection
local field = core_types_helpers.raw_gql_type(
local field = core_types.bare(
parent_field.kind).fields[c.name]
local extra_args = state.extra_arguments[collection_name]
local extra_args_meta =
Expand Down Expand Up @@ -125,7 +124,7 @@ local function create_root_collection(state)
-- `convert` is designed to create GQL type corresponding to a real
-- schema and connections. However it also works with the fake schema.
-- Query/Mutation type must be the Object, so it cannot be nonNull.
root_types[what] = core_types_helpers.nullable(
root_types[what] = core_types.nullable(
types.convert(state, root_schema, {
collection = root_collection,
}))
Expand Down Expand Up @@ -291,7 +290,7 @@ function schema.convert(state, cfg)
assert(collection_type.__type == 'NonNull',
'collection must always has non-null type')
state.nullable_collection_types[collection_name] =
core_types_helpers.nullable(collection_type)
core_types.nullable(collection_type)

-- prepare arguments' types
local object_args_avro = gen_arguments.object_args(cfg, collection_name)
Expand Down
3 changes: 1 addition & 2 deletions graphql/convert_schema/union.lua
Original file line number Diff line number Diff line change
@@ -1,6 +1,5 @@
local yaml = require('yaml')
local core_types = require('graphql.core.types')
local core_types_helpers = require('graphql.convert_schema.core_types_helpers')
local avro_helpers = require('graphql.avro_helpers')
local helpers = require('graphql.convert_schema.helpers')

Expand Down Expand Up @@ -31,7 +30,7 @@ local function box_type(type_to_box, box_field_name, opts)
local gen_argument = opts.gen_argument
local context = opts.context

local gql_true_type = core_types_helpers.nullable(type_to_box)
local gql_true_type = core_types.nullable(type_to_box)

-- Use bare name for the result type (to use in 'on' clause) and full name
-- for the argument type to avoid 'Encountered multiple types' error. See
Expand Down
8 changes: 5 additions & 3 deletions graphql/core/rules.lua
Original file line number Diff line number Diff line change
Expand Up @@ -65,14 +65,16 @@ function rules.argumentsDefinedOnType(node, context)
end

function rules.scalarFieldsAreLeaves(node, context)
if context.objects[#context.objects].__type == 'Scalar' and node.selectionSet then
local field_t = types.bare(context.objects[#context.objects]).__type
if field_t == 'Scalar' and node.selectionSet then
error('Scalar values cannot have subselections')
end
end

function rules.compositeFieldsAreNotLeaves(node, context)
local _type = context.objects[#context.objects].__type
local isCompositeType = _type == 'Object' or _type == 'Interface' or _type == 'Union'
local field_t = types.bare(context.objects[#context.objects]).__type
local isCompositeType = field_t == 'Object' or field_t == 'Interface' or
field_t == 'Union'

if isCompositeType and not node.selectionSet then
error('Composite types must have subselections')
Expand Down
18 changes: 18 additions & 0 deletions graphql/core/types.lua
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,24 @@ function types.list(kind)
}
end

function types.nullable(kind)
assert(type(kind) == 'table', 'kind must be a table, got ' .. type(kind))

if kind.__type ~= 'NonNull' then return kind end

assert(kind.ofType ~= nil, 'kind.ofType must not be nil')
return types.nullable(kind.ofType)
end

function types.bare(kind)
assert(type(kind) == 'table', 'kind must be a table, got ' .. type(kind))

if kind.ofType == nil then return kind end

assert(kind.ofType ~= nil, 'kind.ofType must not be nil')
return types.bare(kind.ofType)
end

function types.scalar(config)
assert(type(config.name) == 'string', 'type name must be provided as a string')
assert(type(config.serialize) == 'function', 'serialize must be a function')
Expand Down
49 changes: 48 additions & 1 deletion test/testdata/common_testdata.lua
Original file line number Diff line number Diff line change
Expand Up @@ -359,7 +359,7 @@ end

function common_testdata.run_queries(gql_wrapper)
local test = tap.test('common')
test:plan(24)
test:plan(26)

local query_1 = [[
query user_by_order($order_id: String) {
Expand Down Expand Up @@ -1219,6 +1219,53 @@ function common_testdata.run_queries(gql_wrapper)

-- }}}

-- {{{ fail cases for scalar w/ fields and complex w/o fields

local query_10 = [[
query order {
order_collection {
order_id {}
}
}

]]

local exp_result_10 = yaml.decode(([[
---
ok: false
err: Scalar values cannot have subselections
]]):strip())

local ok, err = pcall(function()
return gql_wrapper:compile(query_10)
end)

local result = {ok = ok, err = test_utils.strip_error(err)}
test:is_deeply(result, exp_result_10, 'scalar with fields is forbidden')

local query_11 = [[
query order_metainfo {
order_metainfo_collection {
store
}
}
]]

local exp_result_11 = yaml.decode(([[
---
ok: false
err: Composite types must have subselections
]]):strip())

local ok, err = pcall(function()
return gql_wrapper:compile(query_11)
end)

local result = {ok = ok, err = test_utils.strip_error(err)}
test:is_deeply(result, exp_result_11, 'complex without fields is forbidden')

-- }}}

assert(test:check(), 'check plan')
end

Expand Down