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

Commit 08704ed

Browse files
committed
Fix selection existence validation
Fixes #171.
1 parent 2e287c7 commit 08704ed

File tree

7 files changed

+80
-42
lines changed

7 files changed

+80
-42
lines changed

graphql/convert_schema/core_types_helpers.lua

-26
This file was deleted.

graphql/convert_schema/resolve.lua

+5-6
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22

33
local json = require('json')
44
local yaml = require('yaml')
5-
local core_types_helpers = require('graphql.convert_schema.core_types_helpers')
5+
local core_types = require('graphql.core.types')
66

77
local utils = require('graphql.utils')
88
local check = utils.check
@@ -86,17 +86,16 @@ end
8686
function resolve.gen_resolve_function(collection_name, connection,
8787
destination_type, arguments, accessor)
8888
local c = connection
89-
local raw_destination_type = core_types_helpers.raw_gql_type(
90-
destination_type)
89+
local bare_destination_type = core_types.bare(destination_type)
9190

92-
-- capture `raw_destination_type`
91+
-- capture `bare_destination_type`
9392
local function genResolveField(info)
9493
return function(field_name, object, filter, opts)
95-
assert(raw_destination_type.fields[field_name],
94+
assert(bare_destination_type.fields[field_name],
9695
('performing a subrequest by the non-existent ' ..
9796
'field "%s" of the collection "%s"'):format(field_name,
9897
c.destination_collection))
99-
return raw_destination_type.fields[field_name].resolve(
98+
return bare_destination_type.fields[field_name].resolve(
10099
object, filter, info, opts)
101100
end
102101
end

graphql/convert_schema/schema.lua

+3-4
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,6 @@
22

33
local core_types = require('graphql.core.types')
44
local core_schema = require('graphql.core.schema')
5-
local core_types_helpers = require('graphql.convert_schema.core_types_helpers')
65
local gen_arguments = require('graphql.gen_arguments')
76
local arguments = require('graphql.convert_schema.arguments')
87
local types = require('graphql.convert_schema.types')
@@ -64,7 +63,7 @@ local function add_extra_arguments(state, root_types)
6463
-- XXX: support multihead connections
6564
if c.destination_collection then
6665
local collection_name = c.destination_collection
67-
local field = core_types_helpers.raw_gql_type(
66+
local field = core_types.bare(
6867
parent_field.kind).fields[c.name]
6968
local extra_args = state.extra_arguments[collection_name]
7069
local extra_args_meta =
@@ -125,7 +124,7 @@ local function create_root_collection(state)
125124
-- `convert` is designed to create GQL type corresponding to a real
126125
-- schema and connections. However it also works with the fake schema.
127126
-- Query/Mutation type must be the Object, so it cannot be nonNull.
128-
root_types[what] = core_types_helpers.nullable(
127+
root_types[what] = core_types.nullable(
129128
types.convert(state, root_schema, {
130129
collection = root_collection,
131130
}))
@@ -291,7 +290,7 @@ function schema.convert(state, cfg)
291290
assert(collection_type.__type == 'NonNull',
292291
'collection must always has non-null type')
293292
state.nullable_collection_types[collection_name] =
294-
core_types_helpers.nullable(collection_type)
293+
core_types.nullable(collection_type)
295294

296295
-- prepare arguments' types
297296
local object_args_avro = gen_arguments.object_args(cfg, collection_name)

graphql/convert_schema/union.lua

+1-2
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,5 @@
11
local yaml = require('yaml')
22
local core_types = require('graphql.core.types')
3-
local core_types_helpers = require('graphql.convert_schema.core_types_helpers')
43
local avro_helpers = require('graphql.avro_helpers')
54
local helpers = require('graphql.convert_schema.helpers')
65

@@ -31,7 +30,7 @@ local function box_type(type_to_box, box_field_name, opts)
3130
local gen_argument = opts.gen_argument
3231
local context = opts.context
3332

34-
local gql_true_type = core_types_helpers.nullable(type_to_box)
33+
local gql_true_type = core_types.nullable(type_to_box)
3534

3635
-- Use bare name for the result type (to use in 'on' clause) and full name
3736
-- for the argument type to avoid 'Encountered multiple types' error. See

graphql/core/rules.lua

+5-3
Original file line numberDiff line numberDiff line change
@@ -65,14 +65,16 @@ function rules.argumentsDefinedOnType(node, context)
6565
end
6666

6767
function rules.scalarFieldsAreLeaves(node, context)
68-
if context.objects[#context.objects].__type == 'Scalar' and node.selectionSet then
68+
local field_t = types.bare(context.objects[#context.objects]).__type
69+
if field_t == 'Scalar' and node.selectionSet then
6970
error('Scalar values cannot have subselections')
7071
end
7172
end
7273

7374
function rules.compositeFieldsAreNotLeaves(node, context)
74-
local _type = context.objects[#context.objects].__type
75-
local isCompositeType = _type == 'Object' or _type == 'Interface' or _type == 'Union'
75+
local field_t = types.bare(context.objects[#context.objects]).__type
76+
local isCompositeType = field_t == 'Object' or field_t == 'Interface' or
77+
field_t == 'Union'
7678

7779
if isCompositeType and not node.selectionSet then
7880
error('Composite types must have subselections')

graphql/core/types.lua

+18
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,24 @@ function types.list(kind)
2121
}
2222
end
2323

24+
function types.nullable(kind)
25+
assert(type(kind) == 'table', 'kind must be a table, got ' .. type(kind))
26+
27+
if kind.__type ~= 'NonNull' then return kind end
28+
29+
assert(kind.ofType ~= nil, 'kind.ofType must not be nil')
30+
return types.nullable(kind.ofType)
31+
end
32+
33+
function types.bare(kind)
34+
assert(type(kind) == 'table', 'kind must be a table, got ' .. type(kind))
35+
36+
if kind.ofType == nil then return kind end
37+
38+
assert(kind.ofType ~= nil, 'kind.ofType must not be nil')
39+
return types.bare(kind.ofType)
40+
end
41+
2442
function types.scalar(config)
2543
assert(type(config.name) == 'string', 'type name must be provided as a string')
2644
assert(type(config.serialize) == 'function', 'serialize must be a function')

test/testdata/common_testdata.lua

+48-1
Original file line numberDiff line numberDiff line change
@@ -359,7 +359,7 @@ end
359359

360360
function common_testdata.run_queries(gql_wrapper)
361361
local test = tap.test('common')
362-
test:plan(24)
362+
test:plan(26)
363363

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

12201220
-- }}}
12211221

1222+
-- {{{ fail cases for scalar w/ fields and complex w/o fields
1223+
1224+
local query_10 = [[
1225+
query order {
1226+
order_collection {
1227+
order_id {}
1228+
}
1229+
}
1230+
1231+
]]
1232+
1233+
local exp_result_10 = yaml.decode(([[
1234+
---
1235+
ok: false
1236+
err: Scalar values cannot have subselections
1237+
]]):strip())
1238+
1239+
local ok, err = pcall(function()
1240+
return gql_wrapper:compile(query_10)
1241+
end)
1242+
1243+
local result = {ok = ok, err = test_utils.strip_error(err)}
1244+
test:is_deeply(result, exp_result_10, 'scalar with fields is forbidden')
1245+
1246+
local query_11 = [[
1247+
query order_metainfo {
1248+
order_metainfo_collection {
1249+
store
1250+
}
1251+
}
1252+
]]
1253+
1254+
local exp_result_11 = yaml.decode(([[
1255+
---
1256+
ok: false
1257+
err: Composite types must have subselections
1258+
]]):strip())
1259+
1260+
local ok, err = pcall(function()
1261+
return gql_wrapper:compile(query_11)
1262+
end)
1263+
1264+
local result = {ok = ok, err = test_utils.strip_error(err)}
1265+
test:is_deeply(result, exp_result_11, 'complex without fields is forbidden')
1266+
1267+
-- }}}
1268+
12221269
assert(test:check(), 'check plan')
12231270
end
12241271

0 commit comments

Comments
 (0)