-
Notifications
You must be signed in to change notification settings - Fork 3
[WIP] Sb/avro arr #48
Changes from 7 commits
589778a
417c83e
24ec6c4
9a43096
6bd1ca2
31897d6
f0fb9f4
ac9f0ed
8110208
f50f9fc
043d6f9
7714393
470e8e1
0160c69
19b8d8b
1377c75
5af08d8
be8457c
fec3b31
0423ec4
a936771
c8abf95
951e7ea
91bd8bf
148f69f
d9a7623
31abefa
1f2583a
e406a31
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -30,6 +30,14 @@ local function avro_type(avro_schema) | |
return 'record*' | ||
elseif utils.is_array(avro_schema) then | ||
return 'union' | ||
elseif avro_schema.type == 'array' then | ||
return 'array' | ||
elseif avro_schema.type == 'array*' then | ||
return 'array*' | ||
elseif avro_schema.type == 'map' then | ||
return 'map' | ||
elseif avro_schema.type == 'map*' then | ||
return 'map*' | ||
end | ||
elseif type(avro_schema) == 'string' then | ||
if avro_schema == 'int' then | ||
|
@@ -49,16 +57,7 @@ local function avro_type(avro_schema) | |
error('unrecognized avro-schema type: ' .. json.encode(avro_schema)) | ||
end | ||
|
||
-- XXX: recursive skip several NonNull's? | ||
local function nullable(gql_class) | ||
assert(type(gql_class) == 'table', 'gql_class must be a table, got ' .. | ||
type(gql_class)) | ||
|
||
if gql_class.__type ~= 'NonNull' then return gql_class end | ||
|
||
assert(gql_class.ofType ~= nil, 'gql_class.ofType must not be nil') | ||
return gql_class.ofType | ||
end | ||
local nullable = utils.nullable | ||
|
||
local types_long = types.scalar({ | ||
name = 'Long', | ||
|
@@ -96,15 +95,25 @@ local function convert_scalar_type(avro_schema, opts) | |
elseif avro_t == 'string*' then | ||
return types.string | ||
end | ||
|
||
if opts.is_items_type then | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. // This is not more actual because I proposed to remove this option, but I kept this comment here to give you more on our conventions within the project. Please, keep consistency with asserts and default values for options within the 'opts' parameter. Consider 'raise' as the example. More specific: add the local variable with a default value ( There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Don't sure we should pass this option to this function, because it is out of the scope of converting scalar types (this is what the function does). By the way, this option breaks the |
||
error('avro array items must have know scalar type, not: ' .. | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. A user must have info to distinguish not-implemented-yet errors from its mistakes in configuration options (like avro-schemas). Proposed wording: "only scalars are supported as array items for now". |
||
json.encode(avro_schema)) | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. We use 4 spaces as indent. |
||
end | ||
|
||
if raise then | ||
error('unrecognized avro-schema scalar type: ' .. | ||
json.encode(avro_schema)) | ||
json.encode(avro_schema)) | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Hmm. Cannot get you. Why do you remove the indent? Now it feels as broken. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Ping? |
||
end | ||
|
||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. We don't use python-style double empty lines (moreover, here they are within a function, so don't fit PEP8 too). Consider our lua style guidelines: https://tarantool.org/en/doc/1.7/dev_guide/lua_style_guide.html |
||
|
||
return nil | ||
end | ||
|
||
--- Non-recursive version of the @{gql_type} function that returns | ||
--- InputObject instead of Object. | ||
--- An error will be raised in case of fields that are not scalar types | ||
--- as there are no sense in non scalar arguments. | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
|
||
local function gql_argument_type(state, avro_schema) | ||
assert(type(state) == 'table', | ||
'state must be a table, got ' .. type(state)) | ||
|
@@ -115,17 +124,21 @@ local function gql_argument_type(state, avro_schema) | |
assert(type(avro_schema.name) == 'string', | ||
('avro_schema.name must be a string, got %s (avro_schema %s)') | ||
:format(type(avro_schema.name), json.encode(avro_schema))) | ||
|
||
assert(type(avro_schema.fields) == 'table', | ||
('avro_schema.fields must be a table, got %s (avro_schema %s)') | ||
:format(type(avro_schema.fields), json.encode(avro_schema))) | ||
|
||
local fields = {} | ||
for _, field in ipairs(fields) do | ||
for _, field in ipairs(avro_schema.fields) do | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. My bad. Thanks for pointing it out! Filed #53 for that. |
||
|
||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Feel free to use single empty line as the separator for code blocks, but I propose to don't separate a loop header from its body (or a first code block of the body). The same for empty lines before / after If you have some certain view how we should change our code style, let discuss it first, then (maybe) make changes. |
||
assert(type(field.name) == 'string', | ||
('field.name must be a string, got %s (schema %s)') | ||
:format(type(field.name), json.encode(field))) | ||
|
||
local gql_field_type = convert_scalar_type( | ||
field.type, {raise = true}) | ||
|
||
fields[field.name] = { | ||
name = field.name, | ||
kind = types.nonNull(gql_field_type), | ||
|
@@ -149,44 +162,71 @@ local function gql_argument_type(state, avro_schema) | |
end | ||
end | ||
|
||
|
||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Extra empty line. |
||
--- Recursively convert each field of an avro-schema to a graphql type and | ||
--- corresponding argument for an upper graphql type. | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
|
||
--- | ||
--- @tparam table state | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Add XXX comment if you make some kind of placeholder or partial functionality / documentation, but don't finish it in some manner. Here I mean comments for parameters of the function. If you describe it in some other place, you can use |
||
--- @tparam table fields | ||
local function convert_record_fields_to_args(state, fields) | ||
local args = {} | ||
for _, field in ipairs(fields) do | ||
|
||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Extra empty line after the |
||
assert(type(field.name) == 'string', | ||
('field.name must be a string, got %s (schema %s)') | ||
:format(type(field.name), json.encode(field))) | ||
|
||
local gql_class = gql_argument_type(state, field.type) | ||
args[field.name] = nullable(gql_class) | ||
|
||
-- arrays (gql lists) and maps can't be arguments | ||
-- so these kinds are to be skipped | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I don't think we should use the term 'kind' in sense 'a graphql type in the graphql-lua format'. We use 'graphql type' term for that already. General note: I suggest to try hard to use one term for an one abstraction with a project and use different terms for different abstractions. |
||
|
||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Don't separate a code block comment from its code block with empty line. |
||
if (nullable(gql_class) ~= 'List' | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Don't add extra parenthesis around an |
||
and nullable(gql_class) ~= 'Map') then | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Indent here is strange. Use double indent (8 spaces) when you need to carry the line with an |
||
args[field.name] = nullable(gql_class) | ||
end | ||
end | ||
return args | ||
end | ||
|
||
--- Convert each field of an avro-schema to a graphql type and corresponding | ||
--- argument for an upper graphql type. | ||
--- Recursively convert each field of an avro-schema to a graphql type and | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I think that such implementation details is not for the header string of the function. You can write details below, like so:
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Ping? |
||
--- corresponding argument for an upper graphql type. | ||
--- | ||
--- @tparam table state for read state.accessor and previously filled | ||
--- state.types | ||
--- @tparam table fields fields part from an avro-schema | ||
local function convert_record_fields(state, fields) | ||
--- @tparam table opts include is_for_args flag to specify | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. The parameter is redundant. You always set it to There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Ping? |
||
--- case when the function is used to collect arguments | ||
local function convert_record_fields(state, fields, opts) | ||
local res = {} | ||
local object_args = {} | ||
local opts = opts or {} | ||
local is_for_args = opts.is_for_args or false | ||
|
||
for _, field in ipairs(fields) do | ||
assert(type(field.name) == 'string', | ||
('field.name must be a string, got %s (schema %s)') | ||
:format(type(field.name), json.encode(field))) | ||
|
||
res[field.name] = { | ||
name = field.name, | ||
kind = gql_type(state, field.type), | ||
} | ||
object_args[field.name] = nullable(res[field.name].kind) | ||
|
||
|
||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Use single empty line to split code blocks. |
||
-- arrays (gql lists) and maps can't be arguments | ||
if not is_for_args or (nullable(res[field.name].kind) ~= 'List' | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. IMO, it is better to use |
||
and nullable(res[field.name].kind) ~= 'Map') then | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Use double indent for such cases. |
||
object_args[field.name] = nullable(res[field.name].kind) | ||
end | ||
end | ||
return res, object_args | ||
end | ||
|
||
--- The function recursively converts passed avro-schema to a graphql type. | ||
--- The function recursively converts passed avro-schema to a graphql type (kind). | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Personally I keep my lines within 79 symbols. The limit can be discussed. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. As I write above I think we need to omit usage of the term 'kind' for graphql types. |
||
--- | ||
--- @tparam table state for read state.accessor and previously filled | ||
--- state.types | ||
--- state.types (state.types are gql types) | ||
--- @tparam table avro_schema input avro-schema | ||
--- @tparam[opt] table collection table with schema_name, connections fields | ||
--- described a collection (e.g. tarantool's spaces) | ||
|
@@ -212,12 +252,14 @@ gql_type = function(state, avro_schema, collection, collection_name) | |
('collection and collection_name must be nils or ' .. | ||
'non-nils simultaneously, got: %s and %s'):format(type(collection), | ||
type(collection_name))) | ||
|
||
local accessor = state.accessor | ||
assert(accessor ~= nil, 'state.accessor must not be nil') | ||
assert(accessor.select ~= nil, 'state.accessor.select must not be nil') | ||
assert(accessor.list_args ~= nil, | ||
'state.accessor.list_args must not be nil') | ||
|
||
-- type of the top element in the avro schema | ||
local avro_t = avro_type(avro_schema) | ||
|
||
if avro_t == 'record' or avro_t == 'record*' then | ||
|
@@ -230,6 +272,7 @@ gql_type = function(state, avro_schema, collection, collection_name) | |
|
||
local fields, _ = convert_record_fields(state, avro_schema.fields) | ||
|
||
-- if collection param is passed then go over all connections | ||
for _, c in ipairs((collection or {}).connections or {}) do | ||
assert(type(c.type) == 'string', | ||
'connection.type must be a string, got ' .. type(c.type)) | ||
|
@@ -243,6 +286,7 @@ gql_type = function(state, avro_schema, collection, collection_name) | |
assert(type(c.parts) == 'table', | ||
'connection.parts must be a string, got ' .. type(c.parts)) | ||
|
||
-- gql type of connection field | ||
local destination_type = | ||
state.types[c.destination_collection] | ||
assert(destination_type ~= nil, | ||
|
@@ -261,20 +305,24 @@ gql_type = function(state, avro_schema, collection, collection_name) | |
|
||
local c_list_args = state.list_arguments[c.destination_collection] | ||
|
||
-- change fields that are represented by connections | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. That is not about changing, here we just add fields by connections. |
||
fields[c.name] = { | ||
name = c.name, | ||
kind = destination_type, | ||
arguments = c_args, | ||
resolve = function(parent, args_instance, info) | ||
local destination_args_names = {} | ||
local destination_args_values = {} | ||
|
||
for _, part in ipairs(c.parts) do | ||
|
||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Extra empty line after the |
||
assert(type(part.source_field) == 'string', | ||
'part.source_field must be a string, got ' .. | ||
type(part.destination_field)) | ||
assert(type(part.destination_field) == 'string', | ||
'part.destination_field must be a string, got ' .. | ||
type(part.destination_field)) | ||
|
||
destination_args_names[#destination_args_names + 1] = | ||
part.destination_field | ||
destination_args_values[#destination_args_values + 1] = | ||
|
@@ -318,24 +366,50 @@ gql_type = function(state, avro_schema, collection, collection_name) | |
} | ||
end | ||
|
||
-- create gql schema | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. schema -> type |
||
local res = types.object({ | ||
name = collection ~= nil and collection.name or avro_schema.name, | ||
description = 'generated from avro-schema for ' .. | ||
avro_schema.name, | ||
fields = fields, | ||
}) | ||
return avro_t == 'enum' and types.nonNull(res) or res | ||
|
||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Extra empty line before |
||
elseif avro_t == 'enum' then | ||
error('enums not implemented yet') -- XXX | ||
|
||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Extra empty line before |
||
elseif avro_t == 'array' or avro_t == 'array*' then | ||
|
||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Extra empty line after |
||
assert(avro_schema.items ~= nil, | ||
'items field must not be nil in array avro schema') | ||
assert(type(avro_schema.items) == 'string', | ||
'avro_schema.items must be a string, got ' .. type(avro_schema.item)) | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. The line is longer than 79 symbols. |
||
|
||
local gql_items_type = convert_scalar_type(avro_schema.items, | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I think you need to leave XXX comment here that it is not clear what to do with complex types inside arrays (just pass to results or allow to use filters and so on), so we allow only scalar arrays for now. |
||
{is_items_type=true, raise=true}) | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. You duplicate logic of the raise flag with the is_items_type flag, yep? I don't get why. If you want to make custom error message then use |
||
|
||
local gql_array = types.list(gql_items_type) | ||
|
||
if avro_t == 'array*' then | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
|
||
return gql_array | ||
end | ||
|
||
if avro_t == 'array' then | ||
return types.nonNull(gql_array) | ||
end | ||
|
||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Extra empty line before |
||
else | ||
local res = convert_scalar_type(avro_schema, {raise = false}) | ||
if res == nil then | ||
error('unrecognized avro-schema type: ' .. json.encode(avro_schema)) | ||
end | ||
return res | ||
|
||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Extra empty line before |
||
end | ||
|
||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Extra empty line before |
||
end | ||
|
||
|
||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Don't use python-style double empty lines. |
||
local function parse_cfg(cfg) | ||
local state = {} | ||
state.types = utils.gen_booking_table({}) | ||
|
@@ -356,32 +430,41 @@ local function parse_cfg(cfg) | |
|
||
local fields = {} | ||
|
||
for name, collection in pairs(state.collections) do | ||
collection.name = name | ||
for collection_name, collection in pairs(state.collections) do | ||
collection.name = collection_name | ||
assert(collection.schema_name ~= nil, | ||
'collection.schema_name must not be nil') | ||
|
||
local schema = cfg.schemas[collection.schema_name] | ||
assert(schema ~= nil, ('cfg.schemas[%s] must not be nil'):format( | ||
tostring(collection.schema_name))) | ||
assert(schema.name == nil or schema.name == collection.schema_name, | ||
('top-level schema name does not match the name in ' .. | ||
'the schema itself: "%s" vs "%s"'):format(collection.schema_name, | ||
schema.name)) | ||
state.types[name] = gql_type(state, schema, collection, name) | ||
|
||
-- recursively converts all avro types into gql types in the given schema | ||
assert(schema.type == 'record', | ||
'top-level schema must have record avro type, not' .. schema.type) | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Space is missing after 'not'. |
||
state.types[collection_name] = gql_type(state, schema, collection, collection_name) | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
|
||
|
||
-- prepare arguments (their kinds) | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Proposed to don't use the term 'kind' for graphql types (see above). |
||
local _, object_args = convert_record_fields(state, | ||
schema.fields) | ||
schema.fields, {is_for_args=true}) | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Proposed to remove the parameter (see above). |
||
local list_args = convert_record_fields_to_args( | ||
state, accessor:list_args(name)) | ||
state, accessor:list_args(collection_name), {is_for_args=true}) | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
|
||
local args = utils.merge_tables(object_args, list_args) | ||
state.object_arguments[name] = object_args | ||
state.list_arguments[name] = list_args | ||
state.all_arguments[name] = args | ||
|
||
-- list and map (avro array and map) can't be arguments | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I don't get, how this comment related to the code above? Maybe we need to move it to the right place. |
||
|
||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Don't separate a code block comment from it code blocks by an empty line. |
||
state.object_arguments[collection_name] = object_args | ||
state.list_arguments[collection_name] = list_args | ||
state.all_arguments[collection_name] = args | ||
|
||
-- create entry points from collection names | ||
fields[name] = { | ||
kind = types.nonNull(types.list(state.types[name])), | ||
arguments = state.all_arguments[name], | ||
fields[collection_name] = { | ||
kind = types.nonNull(types.list(state.types[collection_name])), | ||
arguments = state.all_arguments[collection_name], | ||
resolve = function(rootValue, args_instance, info) | ||
local object_args_instance = {} -- passed to 'filter' | ||
local list_args_instance = {} -- passed to 'args' | ||
|
@@ -397,7 +480,7 @@ local function parse_cfg(cfg) | |
end | ||
end | ||
local from = nil | ||
return accessor:select(rootValue, name, from, | ||
return accessor:select(rootValue, collection_name, from, | ||
object_args_instance, list_args_instance) | ||
end, | ||
} | ||
|
@@ -414,6 +497,8 @@ local function parse_cfg(cfg) | |
return state | ||
end | ||
|
||
--- The function checks if given query has an appropriate type 'query' | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. It seems that the function does the other action: it checks that one and only one GraphQL operation (query/mutation/subscription) is defined in the AST. That just the minimum check that we got an query AST and not mistakely some other value. |
||
--- (mutations are not supported yet). | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. That note is unrelated to the function. It will doing what it doing despite types of GraphQL operations. |
||
local function assert_gql_query_ast(func_name, ast) | ||
assert(#ast.definitions == 1, | ||
func_name .. ': expected an one query') | ||
|
@@ -425,6 +510,8 @@ local function assert_gql_query_ast(func_name, ast) | |
type(operation_name)) | ||
end | ||
|
||
--- The function just makes some reasonable assertions on input | ||
--- and then call graphql-lua execute. | ||
local function gql_execute(qstate, variables) | ||
assert(qstate.state) | ||
local state = qstate.state | ||
|
@@ -442,6 +529,12 @@ local function gql_execute(qstate, variables) | |
operation_name) | ||
end | ||
|
||
--- The function parses a raw query string, validate the resulting query | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
|
||
--- and make it ready for execution. | ||
--- | ||
--- @tparam table state current state of graphql-lib, including | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. We don't used the term 'graphql-lib' before. |
||
--- schemas, collections and accessor | ||
--- @tparam string query raw query string | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Proposed to omit the word 'raw'. |
||
local function gql_compile(state, query) | ||
assert(type(state) == 'table' and type(query) == 'string', | ||
'use :validate(...) instead of .validate(...)') | ||
|
@@ -458,6 +551,7 @@ local function gql_compile(state, query) | |
ast = ast, | ||
operation_name = operation_name, | ||
} | ||
|
||
local gql_query = setmetatable(qstate, { | ||
__index = { | ||
execute = gql_execute, | ||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
utils.lua is for auxiliary functions that do not contain domain-specific abstractions or logic. We work with graphql-lua types in core/*.lua and tarantool_graphql.lua. It is better to keep these objects within these files (or create new modules working within such terms), but don't mix abstraction layers. In other words, I propose to give back this function to this module. You can create graphql_utils.lua alternatively, but I don't think we have enough helpers to charge it.