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

Commit 00b16e8

Browse files
committed
closes #8
1 parent c933e22 commit 00b16e8

File tree

5 files changed

+84
-98
lines changed

5 files changed

+84
-98
lines changed

graphql/accessor_general.lua

+21-17
Original file line numberDiff line numberDiff line change
@@ -402,7 +402,6 @@ local function build_lookup_index_name(indexes)
402402
return lookup_index_name
403403
end
404404

405-
--@todo add commentary and fix style
406405
local function set_connection_index(c, c_name, c_type, collection_name,
407406
indexes, connection_indexes)
408407
assert(type(c.index_name) == 'string',
@@ -556,36 +555,41 @@ local function validate_collections(collections, schemas)
556555
assert(type(connection.name) == 'string',
557556
'connection.name must be a string, got ' ..
558557
type(connection.name))
559-
-- mind two connections types: simple and union
558+
assert(type(connection.type) == 'string', 'connection.type must' ..
559+
'be a string, got ' .. type(connection.type))
560+
assert(connection.type == '1:1' or connection.type == '1:N',
561+
'connection.type must be \'1:1\' or \'1:N\', got ' ..
562+
connection.type)
560563
if connection.destination_collection then
561564
assert(type(connection.destination_collection) == 'string',
562565
'connection.destination_collection must be a string, got ' ..
563-
type(connection.destination_collection))
566+
type(connection.destination_collection))
564567
assert(type(connection.parts) == 'table',
565-
'connection.parts must be a table, got ' ..
566-
type(connection.parts))
568+
'connection.parts must be a table, got ' ..
569+
type(connection.parts))
567570
assert(type(connection.index_name) == 'string',
568-
'connection.index_name must be a string, got ' ..
569-
type(connection.index_name))
571+
'connection.index_name must be a string, got ' ..
572+
type(connection.index_name))
570573
return
571-
elseif connection.variants then
574+
end
575+
if connection.variants then
572576
for _, v in pairs(connection.variants) do
573-
assert(v.determinant, 'each variant should have a determinant')
574-
assert(type(v.determinant) == 'table', 'variant\'s determinant' ..
575-
'end must be a table, got ' .. type(v.determinant))
577+
assert(type(v.determinant) == 'table', 'variant\'s ' ..
578+
'determinant must be a table, got ' ..
579+
type(v.determinant))
576580
assert(type(v.destination_collection) == 'string',
577-
'variant.destination_collection must be a string, got ' ..
578-
type(v.destination_collection))
581+
'variant.destination_collection must be a string, ' ..
582+
'got ' .. type(v.destination_collection))
579583
assert(type(v.parts) == 'table',
580-
'variant.parts must be a table, got ' .. type(v.parts))
584+
'variant.parts must be a table, got ' .. type(v.parts))
581585
assert(type(v.index_name) == 'string',
582-
'variant.index_name must be a string, got ' ..
583-
type(v.index_name))
586+
'variant.index_name must be a string, got ' ..
587+
type(v.index_name))
584588
end
585589
return
586590
else
587591
assert(false, ('collection doesn\'t have neither destination' ..
588-
'collection nor variants fields'))
592+
'collection nor variants field'))
589593
end
590594
end
591595
end

graphql/core/types.lua

+2
Original file line numberDiff line numberDiff line change
@@ -155,6 +155,8 @@ end
155155
function types.union(config)
156156
assert(type(config.name) == 'string', 'type name must be provided as a string')
157157
assert(type(config.types) == 'table', 'types table must be provided')
158+
assert(type(config.resolveType) == 'function', 'resolveType function must ' ..
159+
'be provided')
158160

159161
local instance = {
160162
__type = 'Union',

graphql/tarantool_graphql.lua

+60-51
Original file line numberDiff line numberDiff line change
@@ -251,16 +251,11 @@ local function convert_record_fields(state, fields)
251251
return res
252252
end
253253

254-
--@todo where to put new format description?
255-
256-
--- The function converts passed simple connection to a field of GraphQL type
257-
--- There are two types on connections: simple and union
258-
254+
--- The function converts passed simple connection to a field of GraphQL type.
259255
---
260-
--- @tparam table state for read state.accessor and previously filled
261-
--- state.types (state.types are gql types)
256+
--- @tparam table state for for collection types
262257
--- @tparam table c simple connection to create field on
263-
--- @tparam table collection_name name of the collection which have given
258+
--- @tparam table collection_name name of the collection which has given
264259
--- connection
265260
local convert_simple_connection = function(state, c, collection_name)
266261
assert(type(c.destination_collection) == 'string',
@@ -292,9 +287,6 @@ local convert_simple_connection = function(state, c, collection_name)
292287
kind = destination_type,
293288
arguments = c_args,
294289
resolve = function(parent, args_instance, info)
295-
--print('print from 295 - resolve of simple connection')
296-
--print('parent - resolve result from parent type')
297-
--require('pl.pretty').dump(parent)
298290
local destination_args_names = {}
299291
local destination_args_values = {}
300292

@@ -354,14 +346,19 @@ local convert_simple_connection = function(state, c, collection_name)
354346
return field
355347
end
356348

349+
--- The function converts passed union connection to a field of GraphQL type.
350+
--- It builds connections between union collection and destination collections
351+
--- (destination collections are 'types' of a 'Union' in GraphQL).
352+
---
353+
--- @tparam table state for collection types
354+
--- @tparam table c union connection to create field on
355+
--- @tparam table collection_name name of the collection which has given
356+
--- connection
357357
local convert_union_connection = function(state, c, collection_name)
358358
local union_types = {}
359359
local collection_to_arguments = {}
360360
local collection_to_list_arguments = {}
361-
-- map from determinant objects to use in resolveType
362-
-- not to use like determinant[determinant_value] = ...
363-
-- use like for k, v in pairs() ...
364-
-- {{hero_type = 'human', number_of_legs = '2'} = 'human_collection', {
361+
365362
local determinant_keys = utils.get_keys(c.variants[1].determinant)
366363
local determinant_to_variant = {}
367364

@@ -397,23 +394,21 @@ local convert_union_connection = function(state, c, collection_name)
397394
collection_to_list_arguments[v.destination_collection] = v_list_args
398395
end
399396

400-
-- should return graphQL type (collection in our terms)
401-
local function resolveType(result)
402-
--@todo fix this as it will work only for human-starship union
403-
if utils.do_have_keys(result, {'name'}) then
404-
return state.types['human_collection']
405-
end
406-
407-
if utils.do_have_keys(result, {'model'}) then
408-
return state.types['starship_collection']
397+
local resolveType = function (result)
398+
for _, v in pairs(c.variants) do
399+
local dest_collection = state.types[v.destination_collection]
400+
if utils.do_have_keys(result, utils.get_keys(dest_collection.fields)) then
401+
return dest_collection
402+
end
409403
end
410404
end
411405

412-
local function resolve_variant(parent)
406+
local resolve_variant = function (parent)
413407
assert(utils.do_have_keys(parent, determinant_keys),
414-
('Parent object of union object doesn\'t have determinant fields' ..
415-
'which are nessesary to determine which resolving variant should' ..
416-
'be used. Union parent object:\n"%s"\n Determinant keys:\n"%s"'):
408+
('Parent object of union object doesn\'t have determinant ' ..
409+
'fields which are nessesary to determine which resolving ' ..
410+
'variant should be used. Union parent object:\n"%s"\n' ..
411+
'Determinant keys:\n"%s"'):
417412
format(yaml.encode(parent), yaml.encode(determinant_keys)))
418413

419414
local resulting_variant
@@ -439,10 +434,10 @@ local convert_union_connection = function(state, c, collection_name)
439434

440435
local field = {
441436
name = c.name,
442-
kind = types.union({name = c.name, types = union_types, resolveType = resolveType}),
437+
kind = types.union({name = c.name, types = union_types,
438+
resolveType = resolveType}),
443439
arguments = nil,
444440
resolve = function(parent, args_instance, info)
445-
--variant for this destination
446441
local v = resolve_variant(parent)
447442
local destination_collection = state.types[v.destination_collection]
448443
local destination_args_names = {}
@@ -503,9 +498,9 @@ local convert_union_connection = function(state, c, collection_name)
503498
return objs
504499
end
505500
end
506-
}
501+
}
507502
return field
508-
end
503+
end
509504

510505
--- The function converts passed connection to a field of GraphQL type
511506
---
@@ -516,11 +511,11 @@ local convert_union_connection = function(state, c, collection_name)
516511
--- connection
517512
local convert_connection_to_field = function(state, connection, collection_name)
518513
assert(type(connection.type) == 'string',
519-
'connection.type must be a string, got ' .. type(connection.type))
514+
'connection.type must be a string, got ' .. type(connection.type))
520515
assert(connection.type == '1:1' or connection.type == '1:N',
521-
'connection.type must be 1:1 or 1:N, got ' .. connection.type)
516+
'connection.type must be 1:1 or 1:N, got ' .. connection.type)
522517
assert(type(connection.name) == 'string',
523-
'connection.name must be a string, got ' .. type(connection.name))
518+
'connection.name must be a string, got ' .. type(connection.name))
524519
assert(connection.destination_collection or connection.variants,
525520
'connection must either destination_collection or variatns field')
526521

@@ -682,7 +677,6 @@ local function parse_cfg(cfg)
682677
{skip_compound = true})
683678
local list_args = convert_record_fields_to_args(
684679
accessor:list_args(collection_name))
685-
686680
local args = utils.merge_tables(object_args, list_args)
687681

688682
state.object_arguments[collection_name] = object_args
@@ -712,10 +706,8 @@ local function parse_cfg(cfg)
712706
local extra = {
713707
qcontext = info.qcontext
714708
}
715-
716-
717709
return accessor:select(rootValue, collection_name, from,
718-
object_args_instance, list_args_instance, extra)
710+
object_args_instance, list_args_instance, extra)
719711
end,
720712
}
721713
end
@@ -779,16 +771,6 @@ local function gql_compile(state, query)
779771
local ast = parse(query)
780772
assert_gql_query_ast('gql_compile', ast)
781773
local operation_name = ast.definitions[1].name.value
782-
--
783-
--print('print from gql_compile - state.schema')
784-
--require('pl.pretty').dump(state.schema)
785-
--
786-
--print('ast')
787-
--require('pl.pretty').dump(ast)
788-
789-
790-
--@todo add custom validation for schemas with unions
791-
--or change insides of validate to process unions the custom way
792774
validate(state.schema, ast)
793775

794776
local qstate = {
@@ -825,7 +807,8 @@ end
825807
--- schema_name = 'schema_name_foo',
826808
--- connections = { // the optional field
827809
--- {
828-
--- name = 'connection_name_bar',
810+
--- type = '1:1' or '1:N',
811+
--- name = 'simple_connection_name',
829812
--- destination_collection = 'collection_baz',
830813
--- parts = {
831814
--- {
@@ -838,7 +821,17 @@ end
838821
--- -- ignored in the graphql
839822
--- -- part
840823
--- },
841-
--- ...
824+
--- {
825+
--- name = 'union_connection_name',
826+
--- type = '1:1' or '1:N',
827+
--- variants = {
828+
--- {
829+
--- see variant format below
830+
--- },
831+
--- ...
832+
--- }
833+
--- },
834+
--- ...
842835
--- },
843836
--- },
844837
--- ...
@@ -872,6 +865,22 @@ end
872865
--- }
873866
--- }),
874867
--- })
868+
---
869+
--- variant format
870+
--- {
871+
--- Source collection must have all fields that are keys in determinant
872+
--- table. Based on the values of these fields right destination collection
873+
--- is determined.
874+
--- determinant = {field_or_source: 'destination_1_value', ...},
875+
--- destination_collection = 'collection_name',
876+
--- parts = {
877+
--- {
878+
--- source_field = 'field_name_source',
879+
--- destination_field = 'field_name_destination'
880+
--- }
881+
--- },
882+
--- index_name = 'index_name'
883+
--- }
875884
function tarantool_graphql.new(cfg)
876885
local state = parse_cfg(cfg)
877886
return setmetatable(state, {

test/local/union.test.lua

+1-1
Original file line numberDiff line numberDiff line change
@@ -57,4 +57,4 @@ testdata.run_queries(gql_wrapper)
5757

5858
testdata.drop_spaces()
5959

60-
os.exit()
60+
os.exit()

test/testdata/union_testdata.lua

-29
Original file line numberDiff line numberDiff line change
@@ -227,35 +227,6 @@ end
227227
function union_testdata.run_queries(gql_wrapper)
228228
local results = ''
229229

230-
231-
232-
--local query = [[
233-
-- query obtainHeroes($hero_id: String) {
234-
-- hero_collection(hero_id: $hero_id) {
235-
-- hero_id
236-
-- hero_type
237-
--
238-
--
239-
-- hero_connection(hero_id: $hero_id){
240-
-- hero_id
241-
-- }
242-
-- }
243-
-- }
244-
--]]
245-
246-
--local query = [[
247-
-- query obtainOrganizationUsers($hero_id: String) {
248-
-- hero_collection(hero_id: $hero_id) {
249-
-- ... on human {
250-
-- name
251-
-- }
252-
-- ... on starship {
253-
-- model
254-
-- }
255-
-- }
256-
-- }
257-
--]]
258-
259230
local query = [[
260231
query obtainHeroes($hero_id: String) {
261232
hero_collection(hero_id: $hero_id) {

0 commit comments

Comments
 (0)