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

Commit cf34fb6

Browse files
committed
Support avro-schema references for records
Fixes #116.
1 parent 54c468c commit cf34fb6

9 files changed

+377
-60
lines changed

graphql/tarantool_graphql.lua

Lines changed: 72 additions & 40 deletions
Original file line numberDiff line numberDiff line change
@@ -56,38 +56,62 @@ local default_instance
5656
-- forward declarations
5757
local gql_type
5858

59-
local function avro_type(avro_schema)
59+
local function is_scalar_type(avro_schema_type)
60+
check(avro_schema_type, 'avro_schema_type', 'string')
61+
62+
local scalar_types = {
63+
['int'] = true,
64+
['int*'] = true,
65+
['long'] = true,
66+
['long*'] = true,
67+
--[[
68+
['float'] = true,
69+
['float*'] = true,
70+
['double'] = true,
71+
['double*'] = true,
72+
['boolean'] = true,
73+
['boolean*'] = true,
74+
]]--
75+
['string'] = true,
76+
['string*'] = true,
77+
['null'] = true,
78+
}
79+
80+
return scalar_types[avro_schema_type] or false
81+
end
82+
83+
local function is_compound_type(avro_schema_type)
84+
check(avro_schema_type, 'avro_schema_type', 'string')
85+
86+
local compound_types = {
87+
['record'] = true,
88+
['record*'] = true,
89+
['array'] = true,
90+
['array*'] = true,
91+
['map'] = true,
92+
['map*'] = true,
93+
}
94+
95+
return compound_types[avro_schema_type] or false
96+
end
97+
98+
local function avro_type(avro_schema, opts)
99+
local opts = opts or {}
100+
local allow_references = opts.allow_references or false
101+
60102
if type(avro_schema) == 'table' then
61-
if avro_schema.type == 'record' then
62-
return 'record'
63-
elseif avro_schema.type == 'record*' then
64-
return 'record*'
65-
elseif utils.is_array(avro_schema) then
103+
if utils.is_array(avro_schema) then
66104
return 'union'
67-
elseif avro_schema.type == 'array' then
68-
return 'array'
69-
elseif avro_schema.type == 'array*' then
70-
return 'array*'
71-
elseif avro_schema.type == 'map' then
72-
return 'map'
73-
elseif avro_schema.type == 'map*' then
74-
return 'map*'
105+
elseif is_compound_type(avro_schema.type) then
106+
return avro_schema.type
107+
elseif allow_references then
108+
return avro_schema
75109
end
76110
elseif type(avro_schema) == 'string' then
77-
if avro_schema == 'int' then
78-
return 'int'
79-
elseif avro_schema == 'int*' then
80-
return 'int*'
81-
elseif avro_schema == 'long' then
82-
return 'long'
83-
elseif avro_schema == 'long*' then
84-
return 'long*'
85-
elseif avro_schema == 'string' then
86-
return 'string'
87-
elseif avro_schema == 'string*' then
88-
return 'string*'
89-
elseif avro_schema == 'null' then
90-
return 'null'
111+
if is_scalar_type(avro_schema) then
112+
return avro_schema
113+
elseif allow_references then
114+
return avro_schema
91115
end
92116
end
93117
error('unrecognized avro-schema type: ' .. json.encode(avro_schema))
@@ -247,17 +271,14 @@ local function convert_record_fields_to_args(fields, opts)
247271
assert(type(field.name) == 'string',
248272
('field.name must be a string, got %s (schema %s)')
249273
:format(type(field.name), json.encode(field)))
250-
251-
-- records, arrays (gql lists) and maps can't be arguments, so these
252-
-- graphql types are to be skipped
253-
local avro_t = avro_type(field.type)
254-
if not skip_compound or (
255-
avro_t ~= 'record' and avro_t ~= 'record*' and
256-
avro_t ~= 'array' and avro_t ~= 'array*' and
257-
avro_t ~= 'map' and avro_t ~= 'map*' and
258-
avro_t ~= 'union') then
259-
260-
local gql_class = gql_argument_type(field.type, field.name)
274+
-- records, arrays (gql lists), maps and unions can't be arguments, so
275+
-- these graphql types are to be skipped;
276+
-- skip_compound == false is the trick for accessor_general-provided
277+
-- record; we don't expect map, array or union here as well as we don't
278+
-- expect avro-schema reference.
279+
local avro_t = avro_type(field.type, {allow_references = true})
280+
if not skip_compound or is_scalar_type(avro_t) then
281+
local gql_class = gql_argument_type(field.type)
261282
args[field.name] = nullable(gql_class)
262283
end
263284
end
@@ -925,7 +946,7 @@ gql_type = function(state, avro_schema, collection, collection_name, field_name)
925946
'state.accessor.list_args must not be nil')
926947

927948
-- type of the top element in the avro-schema
928-
local avro_t = avro_type(avro_schema)
949+
local avro_t = avro_type(avro_schema, {allow_references = true})
929950

930951
if avro_t == 'record' or avro_t == 'record*' then
931952
assert(type(avro_schema.name) == 'string',
@@ -949,6 +970,8 @@ gql_type = function(state, avro_schema, collection, collection_name, field_name)
949970
avro_schema.name,
950971
fields = fields,
951972
})
973+
state.declarations[avro_schema.name] = types.nonNull(res)
974+
state.declarations[avro_schema.name .. '*'] = res
952975
return avro_t == 'record' and types.nonNull(res) or res
953976
elseif avro_t == 'enum' then
954977
error('enums not implemented yet') -- XXX
@@ -980,6 +1003,12 @@ gql_type = function(state, avro_schema, collection, collection_name, field_name)
9801003
elseif avro_t == 'union' then
9811004
return create_gql_union(state, avro_schema, field_name)
9821005
else
1006+
if type(avro_schema) == 'string' then
1007+
if state.declarations[avro_schema] ~= nil then
1008+
return state.declarations[avro_schema]
1009+
end
1010+
end
1011+
9831012
local res = convert_scalar_type(avro_schema, {raise = false})
9841013
if res == nil then
9851014
error('unrecognized avro-schema type: ' ..
@@ -1119,6 +1148,9 @@ local function parse_cfg(cfg)
11191148
state.list_arguments = utils.gen_booking_table({})
11201149
state.all_arguments = utils.gen_booking_table({})
11211150

1151+
-- map from avro-schema names to graphql types
1152+
state.declarations = {}
1153+
11221154
local accessor = cfg.accessor
11231155
assert(accessor ~= nil, 'cfg.accessor must not be nil')
11241156
assert(accessor.select ~= nil, 'cfg.accessor.select must not be nil')

test/common/avro_refs.test.lua

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
#!/usr/bin/env tarantool
2+
3+
local fio = require('fio')
4+
5+
-- require in-repo version of graphql/ sources despite current working directory
6+
package.path = fio.abspath(debug.getinfo(1).source:match("@?(.*/)")
7+
:gsub('/./', '/'):gsub('/+$', '')) .. '/../../?.lua' .. ';' .. package.path
8+
9+
local utils = require('test.utils')
10+
local testdata = require('test.common.lua.test_data_avro_refs')
11+
12+
box.cfg({})
13+
14+
utils.run_testdata(testdata)
15+
16+
os.exit()

test/common/lua/multirunner.lua

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -165,8 +165,11 @@ end
165165
local function run(test_run, init_function, cleanup_function, workload)
166166
-- ensure stable order
167167
local names = {}
168-
for conf_name, _ in pairs(CONFS) do
169-
names[#names + 1] = conf_name
168+
for conf_name, conf in pairs(CONFS) do
169+
-- allow to run w/o test-run
170+
if test_run ~= nil or conf.type == 'space' then
171+
names[#names + 1] = conf_name
172+
end
170173
end
171174
table.sort(names)
172175

0 commit comments

Comments
 (0)