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

Commit af84302

Browse files
committed
Added support for 'skip' and 'include' directives.
Also fixed existing tests on directives - there was wrong syntax, which worked somehow in some cases. Added a little note into README on how to run specific test. Closes #85
1 parent b1e417f commit af84302

File tree

4 files changed

+229
-3
lines changed

4 files changed

+229
-3
lines changed

README.md

+4
Original file line numberDiff line numberDiff line change
@@ -368,6 +368,10 @@ git clone https://github.com/tarantool/graphql.git
368368
git submodule update --recursive --init
369369
make test
370370
```
371+
To run specific test:
372+
```
373+
TEST_RUN_TESTS=common/mutation make test
374+
```
371375

372376
## Requirements
373377

graphql/query_to_avro.lua

+36
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@ local introspection = require(path .. '.introspection')
1010
local query_util = require(path .. '.query_util')
1111
local avro_helpers = require('graphql.avro_helpers')
1212
local convert_schema_helpers = require('graphql.convert_schema.helpers')
13+
local check = require('graphql.utils').check
1314

1415
-- module functions
1516
local query_to_avro = {}
@@ -97,6 +98,41 @@ local function field_to_avro(object_type, fields, context)
9798

9899
local fieldTypeAvro = gql_type_to_avro(fieldType.kind, subSelections,
99100
context)
101+
102+
-- Currently we support only 'include' and 'skip' directives.
103+
-- Both of them affect resulting avro-schema the same
104+
-- way: field with directive becomes nullable, if it's
105+
-- already not. Nullable field does not change. If it is
106+
-- a 1:N connection then it's 'array' field becomes 'array*'.
107+
-- If there are more then one directive on a field then
108+
-- all works the same way, like it is only one directive.
109+
-- (But we still check all directives to be 'include' or
110+
-- 'skip').
111+
if firstField.directives ~= nil then
112+
for _, d in ipairs(firstField.directives) do
113+
check(d.name, "directive.name", "table")
114+
check(d.arguments, "directive.arguments", "table")
115+
check(d.kind, "directive.kind", "string")
116+
assert(d.kind == "directive")
117+
check(d.name.value, "directive.name.value", "string")
118+
assert(d.name.value == "include" or d.name.value == "skip",
119+
"Only 'include' and 'skip' directives are supported for now")
120+
end
121+
if type(fieldTypeAvro) == "string" then
122+
if string.sub(fieldTypeAvro, -1) ~= '*' then
123+
fieldTypeAvro = fieldTypeAvro .. '*'
124+
end
125+
end
126+
if type(fieldTypeAvro) == "table" then
127+
-- GraphQL Interface and Union are not supported yet.
128+
-- Appropriate assertions are made above in gql_type_to_avro()
129+
check(fieldTypeAvro.type, "fieldTypeAvro.type", "string")
130+
if string.sub(fieldTypeAvro.type, -1) ~= '*' then
131+
fieldTypeAvro.type = fieldTypeAvro.type .. '*'
132+
end
133+
end
134+
end
135+
100136
return {
101137
name = convert_schema_helpers.base_name(fieldName),
102138
type = fieldTypeAvro,

test/common/directives.test.lua

+4-3
Original file line numberDiff line numberDiff line change
@@ -21,8 +21,8 @@ local function run_queries(gql_wrapper)
2121
order_collection(description: $description) {
2222
order_id
2323
description
24-
user_connection @include(if: $include,
25-
first_name: $first_name) {
24+
user_connection(first_name: $first_name)
25+
@include(if: $include) {
2626
user_id
2727
last_name
2828
first_name @skip(if: $nested_skip)
@@ -92,7 +92,8 @@ local function run_queries(gql_wrapper)
9292
order_collection(description: $description) {
9393
order_id
9494
description
95-
user_connection @skip(if: $skip, first_name: $first_name) {
95+
user_connection(first_name: $first_name)
96+
@skip(if: $skip) {
9697
user_id
9798
last_name
9899
first_name @include(if: $nested_include)
+185
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,185 @@
1+
#!/usr/bin/env tarantool
2+
local fio = require('fio')
3+
local yaml = require('yaml')
4+
local avro = require('avro_schema')
5+
local test = require('tap').test('to avro schema')
6+
local testdata = require('test.testdata.common_testdata')
7+
local graphql = require('graphql')
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' .. ';' .. package.path
12+
13+
test:plan(5)
14+
15+
box.cfg{}
16+
17+
testdata.init_spaces()
18+
local meta = testdata.get_test_metadata()
19+
testdata.fill_test_data(box.space, meta)
20+
21+
local accessor = graphql.accessor_space.new({
22+
schemas = meta.schemas,
23+
collections = meta.collections,
24+
service_fields = meta.service_fields,
25+
indexes = meta.indexes,
26+
})
27+
28+
local gql_wrapper = graphql.new({
29+
schemas = meta.schemas,
30+
collections = meta.collections,
31+
accessor = accessor,
32+
})
33+
34+
local query = [[
35+
query order_by_id($order_id: String, $include_description: Boolean,
36+
$skip_discount: Boolean, $include_user: Boolean,
37+
$include_user_first_name: Boolean, $user_id: String,
38+
$include_order_meta: Boolean) {
39+
order_collection(order_id: $order_id) {
40+
order_id
41+
description @include(if: $include_description)
42+
discount @skip(if: $skip_discount)
43+
user_connection(user_id: "user_id_1")
44+
@include(if: $include_user) {
45+
user_id
46+
first_name @include(if: $include_user_first_name)
47+
}
48+
order_metainfo_connection(order_id: $order_id)
49+
@skip(if: $include_order_meta) {
50+
order_metainfo_id
51+
}
52+
}
53+
user_collection(user_id: $user_id) @include(if: $include_user) {
54+
user_id
55+
first_name
56+
}
57+
}
58+
]]
59+
60+
local expected_avro_schema = [[
61+
type: record
62+
name: Query
63+
fields:
64+
- name: order_collection
65+
type:
66+
type: array
67+
items:
68+
type: record
69+
fields:
70+
- name: order_id
71+
type: string
72+
- name: description
73+
type: string*
74+
- name: discount
75+
type: double*
76+
- name: user_connection
77+
type:
78+
type: record*
79+
fields:
80+
- name: user_id
81+
type: string
82+
- name: first_name
83+
type: string*
84+
name: user_collection
85+
namespace: Query.order_collection
86+
- name: order_metainfo_connection
87+
type:
88+
type: record*
89+
fields:
90+
- name: order_metainfo_id
91+
type: string
92+
name: order_metainfo_collection
93+
namespace: Query.order_collection
94+
name: order_collection
95+
namespace: Query
96+
- name: user_collection
97+
type:
98+
type: array*
99+
items:
100+
type: record
101+
fields:
102+
- name: user_id
103+
type: string
104+
- name: first_name
105+
type: string
106+
name: user_collection
107+
namespace: Query
108+
]]
109+
110+
local gql_query = gql_wrapper:compile(query)
111+
112+
local avro_from_query = gql_query:avro_schema()
113+
expected_avro_schema = yaml.decode(expected_avro_schema)
114+
test:is_deeply(avro_from_query, expected_avro_schema,
115+
'comparision between expected and generated (from query) avro-schemas')
116+
117+
local ok, compiled_schema = avro.create(avro_from_query)
118+
assert(ok, tostring(compiled_schema))
119+
120+
local variables_1 = {
121+
order_id = 'order_id_1',
122+
user_id = 'user_id_1',
123+
include_description = true,
124+
skip_discount = false,
125+
include_user = true,
126+
include_user_first_name = false,
127+
include_order_meta = true
128+
}
129+
130+
local result_1 = gql_query:execute(variables_1)
131+
result_1 = result_1.data
132+
local result_expected_1 = yaml.decode([[
133+
user_collection:
134+
- user_id: user_id_1
135+
first_name: Ivan
136+
order_collection:
137+
- order_id: order_id_1
138+
discount: 0
139+
description: first order of Ivan
140+
user_connection:
141+
user_id: user_id_1
142+
]])
143+
144+
test:is_deeply(result_1, result_expected_1,
145+
'comparision between expected and actual query response')
146+
147+
local ok, err = avro.validate(compiled_schema, result_1)
148+
assert(ok, tostring(err))
149+
test:is(ok, true, 'query response validation by avro')
150+
151+
local variables_2 = {
152+
order_id = 'order_id_1',
153+
user_id = 'user_id_1',
154+
include_description = false,
155+
skip_discount = true,
156+
include_user = true,
157+
include_user_first_name = true,
158+
include_order_meta = false
159+
}
160+
161+
local result_2 = gql_query:execute(variables_2)
162+
result_2 = result_2.data
163+
local result_expected_2 = yaml.decode([[
164+
user_collection:
165+
- user_id: user_id_1
166+
first_name: Ivan
167+
order_collection:
168+
- order_id: order_id_1
169+
user_connection:
170+
user_id: user_id_1
171+
first_name: Ivan
172+
order_metainfo_connection:
173+
order_metainfo_id: order_metainfo_id_1
174+
]])
175+
176+
test:is_deeply(result_2, result_expected_2,
177+
'comparision between expected and actual query response')
178+
179+
local ok, err = avro.validate(compiled_schema, result_2)
180+
assert(ok, tostring(err))
181+
test:is(ok, true, 'query response validation by avro')
182+
183+
assert(test:check(), 'check plan')
184+
185+
os.exit()

0 commit comments

Comments
 (0)