Skip to content

Commit 9633093

Browse files
committed
Do not hide a field with a connection
Closes tarantool#170.
1 parent d159287 commit 9633093

File tree

2 files changed

+179
-0
lines changed

2 files changed

+179
-0
lines changed

graphql/convert_schema/schema.lua

Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -221,6 +221,39 @@ local function add_connection_arguments(state)
221221
end)
222222
end
223223

224+
--- Check there are no connections named as uppermost fields of a schema and
225+
--- there are no connections with the same name.
226+
local function check_connection_names(schema, collection)
227+
assert(collection.name ~= nil)
228+
229+
local connection_names = {}
230+
local field_names = {}
231+
232+
for _, field in ipairs(schema.fields) do
233+
local name = field.name
234+
assert(name ~= nil)
235+
assert(field_names[name] == nil)
236+
field_names[name] = true
237+
end
238+
239+
for _, connection in ipairs(collection.connections) do
240+
local name = connection.name
241+
assert(name ~= nil)
242+
if connection_names[name] ~= nil then
243+
local err = ('[collection "%s"] two connections are named "%s"')
244+
:format(collection.name, name)
245+
error(err)
246+
end
247+
if field_names[name] ~= nil then
248+
local err = ('[collection "%s"] the connection "%s" is named ' ..
249+
'as a schema field'):format(collection.name, name)
250+
error(err)
251+
end
252+
connection_names[name] = true
253+
field_names[name] = true
254+
end
255+
end
256+
224257
function schema.convert(state, cfg)
225258
-- collection type is always record, so always non-null; we can lazily
226259
-- evaluate non-null type from nullable type, but not vice versa, so we
@@ -275,6 +308,8 @@ function schema.convert(state, cfg)
275308
'top-level schema must have record avro type, got ' ..
276309
tostring(schema.type))
277310

311+
check_connection_names(schema, collection)
312+
278313
-- fill schema with expanded references
279314
local e_schema = avro_helpers.expand_references(schema)
280315
cfg.e_schemas[collection.schema_name] = e_schema
Lines changed: 144 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,144 @@
1+
#!/usr/bin/env tarantool
2+
3+
-- https://github.com/tarantool/graphql/issues/170
4+
5+
local fio = require('fio')
6+
local json = require('json')
7+
local tap = require('tap')
8+
9+
-- require in-repo version of graphql/ sources despite current working directory
10+
package.path = fio.abspath(debug.getinfo(1).source:match("@?(.*/)")
11+
:gsub('/./', '/'):gsub('/+$', '')) .. '/../../?.lua' .. ';' ..
12+
package.path
13+
14+
local graphql = require('graphql')
15+
local utils = require('graphql.utils')
16+
local test_utils = require('test.test_utils')
17+
18+
local test = tap.test('connections do not hide fields')
19+
20+
box.cfg{wal_mode='none'}
21+
test:plan(3)
22+
23+
local schemas = json.decode([[{
24+
"foo": {
25+
"name": "foo",
26+
"type": "record",
27+
"fields": [
28+
{ "name": "foo_id", "type": "string" },
29+
{ "name": "bar", "type": "string" }
30+
]
31+
},
32+
"bar": {
33+
"name": "bar",
34+
"type": "record",
35+
"fields": [
36+
{ "name": "bar_id", "type": "string" }
37+
]
38+
}
39+
}]])
40+
41+
local collections_1 = json.decode([[{
42+
"foo": {
43+
"schema_name": "foo",
44+
"connections": [
45+
{
46+
"type": "1:1",
47+
"name": "bar",
48+
"destination_collection": "bar",
49+
"parts": [
50+
{
51+
"source_field": "bar",
52+
"destination_field": "bar_id"
53+
}
54+
],
55+
"index_name": "bar_id"
56+
}
57+
]
58+
},
59+
"bar": {
60+
"schema_name": "bar",
61+
"connections": []
62+
}
63+
}]])
64+
65+
local collections_2 = table.deepcopy(collections_1)
66+
collections_2.foo.connections[1].type = '1:N'
67+
68+
local collections_3 = table.deepcopy(collections_1)
69+
collections_3.foo.connections[1].name = 'bar_c'
70+
table.insert(collections_3.foo.connections, collections_3.foo.connections[1])
71+
72+
local service_fields = {
73+
foo = {},
74+
bar = {},
75+
}
76+
77+
local indexes = {
78+
foo = {
79+
foo_id = {
80+
service_fields = {},
81+
fields = {'foo_id'},
82+
index_type = 'tree',
83+
unique = true,
84+
primary = true,
85+
},
86+
},
87+
bar = {
88+
bar_id = {
89+
service_fields = {},
90+
fields = {'bar_id'},
91+
index_type = 'tree',
92+
unique = true,
93+
primary = true,
94+
},
95+
},
96+
}
97+
98+
local cfg_1 = utils.merge_tables({
99+
schemas = schemas,
100+
collections = collections_1,
101+
service_fields = service_fields,
102+
indexes = indexes,
103+
accessor = 'space',
104+
}, test_utils.test_conf_graphql_opts())
105+
106+
local cfg_2 = table.deepcopy(cfg_1)
107+
cfg_2.collections = collections_2
108+
109+
local cfg_3 = table.deepcopy(cfg_1)
110+
cfg_3.collections = collections_3
111+
112+
-- schema field name clash with 1:1 connection name
113+
-- ------------------------------------------------
114+
115+
local exp_err = '[collection "foo"] the connection "bar" is named ' ..
116+
'as a schema field'
117+
118+
local ok, err = pcall(graphql.new, cfg_1)
119+
120+
test:is_deeply({ok, utils.strip_error(err)}, {false, exp_err},
121+
'do not hide fields for 1:1 connections')
122+
123+
-- schema field name clash with 1:N connection name
124+
-- ------------------------------------------------
125+
126+
local exp_err = '[collection "foo"] the connection "bar" is named ' ..
127+
'as a schema field'
128+
129+
local ok, err = pcall(graphql.new, cfg_2)
130+
131+
test:is_deeply({ok, utils.strip_error(err)}, {false, exp_err},
132+
'do not hide fields for 1:N connections')
133+
134+
-- connections names clash
135+
-- -----------------------
136+
137+
local exp_err = '[collection "foo"] two connections are named "bar_c"'
138+
139+
local ok, err = pcall(graphql.new, cfg_3)
140+
141+
test:is_deeply({ok, utils.strip_error(err)}, {false, exp_err},
142+
'do not hide a connection with a connection')
143+
144+
os.exit(test:check() == true and 0 or 1)

0 commit comments

Comments
 (0)