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

Commit 7ec595f

Browse files
KhatskevichSudoBobo
authored andcommitted
* Closes #8.
1 parent f242a61 commit 7ec595f

20 files changed

+3746
-148
lines changed

README.md

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -97,7 +97,8 @@ make test
9797

9898
* For use: tarantool, lulpeg, >=tarantool/shard-1.1-91-gfa88bf8 (optional),
9999
tarantool/avro-schema.
100-
* For test (additionally to 'for use'): python 2.7, virtualenv, luacheck.
100+
* For test (additionally to 'for use'): python 2.7, virtualenv, luacheck,
101+
>=tarantool/shard-1.1-92-gec1a27e.
101102
* For building apidoc (additionally to 'for use'): ldoc.
102103

103104
## License

graphql/accessor_general.lua

Lines changed: 261 additions & 53 deletions
Large diffs are not rendered by default.

graphql/core/execute.lua

Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -47,9 +47,16 @@ local function shouldIncludeNode(selection, context)
4747
end
4848

4949
local function doesFragmentApply(fragment, type, context)
50+
51+
--print('print from doesFragmentApply - 51')
52+
--print('fragment')
53+
--require('pl.pretty').dump(fragment)
54+
5055
if not fragment.typeCondition then return true end
5156

5257
local innerType = typeFromAST(fragment.typeCondition, context.schema)
58+
--print('innerType')
59+
--require('pl.pretty').dump(innerType)
5360

5461
if innerType == type then
5562
return true
@@ -156,6 +163,13 @@ local function completeValue(fieldType, result, subSelections, context)
156163
local completedResult = completeValue(innerType, result, subSelections, context)
157164

158165
if completedResult == nil then
166+
--@todo remove comments
167+
--print('print from completeValue')
168+
--print('result')
169+
--require('pl.pretty').dump(result)
170+
--print('fieldType')
171+
--require('pl.pretty').dump(fieldType)
172+
159173
error('No value provided for non-null ' .. (innerType.name or innerType.__type))
160174
end
161175

@@ -175,6 +189,15 @@ local function completeValue(fieldType, result, subSelections, context)
175189

176190
local values = {}
177191
for i, value in ipairs(result) do
192+
--@todo remove comments
193+
--print('print for ipairs(result) 195')
194+
--require('pl.pretty').dump(result)
195+
--print('value')
196+
--require('pl.pretty').dump(value)
197+
--print('subSelections')
198+
--require('pl.pretty').dump(subSelections)
199+
200+
178201
values[i] = completeValue(innerType, value, subSelections, context)
179202
end
180203

@@ -200,6 +223,11 @@ local function getFieldEntry(objectType, object, fields, context)
200223
local firstField = fields[1]
201224
local fieldName = firstField.name.value
202225
local responseKey = getFieldResponseKey(firstField)
226+
--print('print from getFieldEntry')
227+
--print('objectType')
228+
--require('pl.pretty').dump(objectType)
229+
--print('object itself')
230+
--require('pl.pretty').dump(object)
203231
local fieldType = introspection.fieldMap[fieldName] or objectType.fields[fieldName]
204232

205233
if fieldType == nil then
@@ -236,6 +264,16 @@ local function getFieldEntry(objectType, object, fields, context)
236264
end
237265

238266
evaluateSelections = function(objectType, object, selections, context)
267+
268+
--@todo remove debug
269+
--print('EVALUETE SELECTIONS')
270+
----print('objectType')
271+
----require('pl.pretty').dump(objectType)
272+
--print('object')
273+
--require('pl.pretty').dump(object)
274+
--
275+
--print('EVALUETE SELECTIONS CLOSE')
276+
239277
local groupedFieldSet = collectFields(objectType, selections, {}, {}, context)
240278

241279
return util.map(groupedFieldSet, function(fields)

graphql/tarantool_graphql.lua

Lines changed: 47 additions & 39 deletions
Original file line numberDiff line numberDiff line change
@@ -280,7 +280,7 @@ local convert_simple_connection = function(state, c, collection_name)
280280
error('unknown connection type: ' .. tostring(c.type))
281281
end
282282

283-
local c_list_args = state.list_arguments[c.destination_collection]
283+
local c_list_args = state.list_arguments[c.destination_collection]
284284

285285
local field = {
286286
name = c.name,
@@ -631,6 +631,45 @@ gql_type = function(state, avro_schema, collection, collection_name)
631631
end
632632
end
633633

634+
--- Create virtual root collection `Query`, which has connections to any
635+
--- collection.
636+
---
637+
--- Actually, each GQL query starts its execution from the `Query` collection.
638+
--- That is why it shoult contain connections to any collection.
639+
---
640+
--- @tparam table state dictionary which contains all information about the
641+
--- schema, arguments, types...
642+
local function create_root_collection(state)
643+
local root_connections = {}
644+
-- The fake connections have 1:N mechanics.
645+
-- Create one connection for each collection.
646+
for collection_name, collection in pairs(state.collections) do
647+
table.insert(root_connections, {
648+
parts = {},
649+
name = collection_name,
650+
destination_collection = collection_name,
651+
type = "1:N"
652+
})
653+
end
654+
local root_schema = {
655+
type = "record",
656+
name = "Query",
657+
-- The fake root has no fields.
658+
fields = {}
659+
}
660+
local root_collection = {
661+
name = "Query",
662+
connections = root_connections
663+
}
664+
665+
-- `gql_type` is designed to create GQL type corresponding to a real schema
666+
-- and connections. However it also works with the fake schema.
667+
local root_type = gql_type(state, root_schema, root_collection, "Query")
668+
state.schema = schema.create({
669+
query = root_type
670+
})
671+
end
672+
634673
local function parse_cfg(cfg)
635674
local state = {}
636675
state.types = utils.gen_booking_table({})
@@ -649,8 +688,11 @@ local function parse_cfg(cfg)
649688
local collections = table.copy(cfg.collections)
650689
state.collections = collections
651690

652-
local fields = {}
653-
691+
-- Prepare types which represents:
692+
-- - Avro schemas (collections)
693+
-- - scalar field arguments (used to filter objects by value stored in it's
694+
-- field)
695+
-- - list arguments (offset, limit...)
654696
for collection_name, collection in pairs(state.collections) do
655697
collection.name = collection_name
656698
assert(collection.schema_name ~= nil,
@@ -683,43 +725,9 @@ local function parse_cfg(cfg)
683725
state.list_arguments[collection_name] = list_args
684726
state.all_arguments[collection_name] = args
685727

686-
-- create entry points from collection names
687-
fields[collection_name] = {
688-
kind = types.nonNull(types.list(state.types[collection_name])),
689-
arguments = state.all_arguments[collection_name],
690-
resolve = function(rootValue, args_instance, info)
691-
local object_args_instance = {} -- passed to 'filter'
692-
local list_args_instance = {} -- passed to 'args'
693-
for k, v in pairs(args_instance) do
694-
if list_args[k] ~= nil then
695-
list_args_instance[k] = v
696-
elseif state.object_arguments[k] ~= nil then
697-
object_args_instance[k] = v
698-
else
699-
error(('cannot found "%s" field ("%s" value) ' ..
700-
'within allowed fields'):format(tostring(k),
701-
tostring(v)))
702-
end
703-
end
704-
local from = nil
705-
706-
local extra = {
707-
qcontext = info.qcontext
708-
}
709-
return accessor:select(rootValue, collection_name, from,
710-
object_args_instance, list_args_instance, extra)
711-
end,
712-
}
713728
end
714-
715-
local schema = schema.create({
716-
query = types.object({
717-
name = 'Query',
718-
fields = fields,
719-
})
720-
})
721-
state.schema = schema
722-
729+
-- create fake root `Query` collection
730+
create_root_collection(state)
723731
return state
724732
end
725733

test/common/lua/multirunner.lua

Lines changed: 0 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -30,13 +30,6 @@ end
3030

3131
local function shard_cleanup(test_run, servers)
3232
test_run:drop_cluster(servers)
33-
-- crutch!!
34-
-- test_run.lua do not delete servers
35-
-- todo: should be removed after #83 is fixed in test-run
36-
local drop_cluster_cmd3 = 'delete server %s'
37-
for _, name in ipairs(servers) do
38-
test_run:cmd(drop_cluster_cmd3:format(name))
39-
end
4033
end
4134

4235
local function for_each_server(shard, func)

test/common/query_timeout.test.lua

Lines changed: 72 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,72 @@
1+
#!/usr/bin/env tarantool
2+
local multirunner = require('multirunner')
3+
local data = require('test_data_user_order')
4+
local test_run = require('test_run').new()
5+
local tap = require('tap')
6+
local graphql = require('graphql')
7+
8+
box.cfg({})
9+
local test = tap.test('result cnt')
10+
test:plan(3)
11+
12+
-- require in-repo version of graphql/ sources despite current working directory
13+
local fio = require('fio')
14+
package.path = fio.abspath(debug.getinfo(1).source:match("@?(.*/)")
15+
:gsub('/./', '/'):gsub('/+$', '')) .. '/../../?.lua' .. ';' .. package.path
16+
17+
local function run(setup_name, shard)
18+
print(setup_name)
19+
local accessor_class
20+
local virtbox
21+
-- SHARD
22+
if shard ~= nil then
23+
accessor_class = graphql.accessor_shard
24+
virtbox = shard
25+
else
26+
accessor_class = graphql.accessor_space
27+
virtbox = box.space
28+
end
29+
local accessor = accessor_class.new({
30+
schemas = data.meta.schemas,
31+
collections = data.meta.collections,
32+
service_fields = data.meta.service_fields,
33+
indexes = data.meta.indexes,
34+
timeout_ms = 0.001
35+
})
36+
37+
local gql_wrapper = graphql.new({
38+
schemas = data.meta.schemas,
39+
collections = data.meta.collections,
40+
accessor = accessor,
41+
})
42+
data.fill_test_data(virtbox)
43+
local query = [[
44+
query object_result_max {
45+
user_collection {
46+
id
47+
last_name
48+
first_name
49+
order_connection {
50+
id
51+
user_id
52+
description
53+
}
54+
}
55+
}
56+
]]
57+
58+
local gql_query = gql_wrapper:compile(query)
59+
local variables = {
60+
}
61+
local ok, result = pcall(gql_query.execute, gql_query, variables)
62+
assert(ok == false, 'this test should fail')
63+
test:like(result, 'query execution timeout exceeded', 'timeout test')
64+
65+
end
66+
67+
multirunner.run(test_run,
68+
data.init_spaces,
69+
data.drop_spaces,
70+
run)
71+
72+
os.exit(test:check() == true and 0 or 1)

0 commit comments

Comments
 (0)