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

Commit e5f9240

Browse files
committed
Disable mutations for avro-schema-2* by default
Added `enable_mutations` option to forcely enable it.
1 parent ad77f55 commit e5f9240

File tree

6 files changed

+131
-35
lines changed

6 files changed

+131
-35
lines changed

README.md

+5
Original file line numberDiff line numberDiff line change
@@ -126,6 +126,11 @@ local result = compiled_query:execute(variables)
126126

127127
### Mutations
128128

129+
Mutations are disabled for avro-schema-2\*, because it can work incorrectly for
130+
schemas with nullable types (ones whose marked with asterisk). Mutations still
131+
can be enabled with the `enable_mutations = true` option, but use it with
132+
caution. Don't enable this option with schemas involve nullable types.
133+
129134
#### Insert
130135

131136
Example with an object passed from a variable:

graphql/accessor_general.lua

+46-24
Original file line numberDiff line numberDiff line change
@@ -1419,6 +1419,10 @@ end
14191419

14201420
--- XXX
14211421
local function extra_args(self, collection_name)
1422+
if not self.settings.enable_mutations then
1423+
return {}, {}
1424+
end
1425+
14221426
local collection = self.collections[collection_name]
14231427
local schema_name = collection.schema_name
14241428

@@ -1480,29 +1484,23 @@ end
14801484
--- Provided `funcs` argument determines certain functions for retrieving
14811485
--- tuples.
14821486
---
1483-
--- @tparam table opts `schemas`, `collections`, `service_fields`, `indexes` and
1484-
--- `collection_use_tomap` ({[collection_name] = whether objects in collection
1485-
--- collection_name intended to be unflattened using tuple:tomap({names_only = true})
1486-
--- method instead of compiled_avro_schema.unflatten(tuple), ...})
1487-
--- to give the data accessor all needed meta-information re data; the format is
1488-
--- shown below; additional attributes `resulting_object_cnt_max` and
1489-
--- `fetched_object_cnt_max` are optional positive numbers which help to control
1490-
--- query behaviour in case it requires more resources than expected _(default
1491-
--- value is 10,000)_; `timeout_ms` _(default is 1000)_
1492-
---
1493-
--- @tparam table funcs set of functions:
1494-
---
1495-
--- * `is_collection_exists`,
1496-
--- * `get_index`,
1497-
--- * `get_primary_index`,
1498-
--- * `unflatten_tuple`,
1499-
--- * `flatten_object`,
1500-
--- * `insert_tuple`.
1501-
---
1502-
--- They allows this abstract data accessor behaves in the certain way (say,
1503-
--- like space data accessor or shard data accessor); consider the
1504-
--- `accessor_space` and the `accessor_shard` modules documentation for these
1505-
--- functions description.
1487+
--- @tparam table opts set of options:
1488+
---
1489+
--- * `schemas`,
1490+
--- * `collections`,
1491+
--- * `service_fields`,
1492+
--- * `indexes`,
1493+
--- * `collection_use_tomap`: ({[collection_name] = whether objects in
1494+
--- collection `collection_name` intended to be unflattened using
1495+
--- `tuple:tomap({names_only = true}` method instead of
1496+
--- `compiled_avro_schema.unflatten(tuple), ...}`),
1497+
--- * `resulting_object_cnt_max` and `fetched_object_cnt_max` are optional
1498+
--- positive numbers which help to control query behaviour in case it
1499+
--- requires more resources than expected _(default value is 10,000 for
1500+
--- both)_,
1501+
--- * `timeout_ms` _(default is 1000)_,
1502+
--- * `enable_mutations`: boolean flag _(default is `false` for avro-schema-2*
1503+
--- and `true` for avro-schema-3*)_.
15061504
---
15071505
--- For examples of `opts.schemas` and `opts.collections` consider the
15081506
--- @{tarantool_graphql.new} function description.
@@ -1529,6 +1527,20 @@ end
15291527
--- ...
15301528
--- }
15311529
---
1530+
--- @tparam table funcs set of functions:
1531+
---
1532+
--- * `is_collection_exists`,
1533+
--- * `get_index`,
1534+
--- * `get_primary_index`,
1535+
--- * `unflatten_tuple`,
1536+
--- * `flatten_object`,
1537+
--- * `insert_tuple`.
1538+
---
1539+
--- They allows this abstract data accessor behaves in the certain way (say,
1540+
--- like space data accessor or shard data accessor); consider the
1541+
--- `accessor_space` and the `accessor_shard` modules documentation for these
1542+
--- functions description.
1543+
---
15321544
--- @treturn table data accessor instance, a table with the two methods
15331545
--- (`select` and `arguments`) as described in the @{tarantool_graphql.new}
15341546
--- function description.
@@ -1548,6 +1560,14 @@ function accessor_general.new(opts, funcs)
15481560
DEF_FETCHED_OBJECT_CNT_MAX
15491561
-- TODO: move this setting to `tgql.compile` after #59
15501562
local timeout_ms = opts.timeout_ms or DEF_TIMEOUT_MS
1563+
-- Mutations are disabled for avro-schema-2*, because it can work
1564+
-- incorrectly for schemas with nullable types.
1565+
local enable_mutations
1566+
if opts.enable_mutations == nil then
1567+
enable_mutations = avro_helpers.major_avro_schema_version() == 3
1568+
else
1569+
enable_mutations = opts.enable_mutations
1570+
end
15511571

15521572
assert(type(schemas) == 'table',
15531573
'schemas must be a table, got ' .. type(schemas))
@@ -1569,6 +1589,7 @@ function accessor_general.new(opts, funcs)
15691589
assert(timeout_ms <= TIMEOUT_INFINITY,
15701590
('timeouts more then graphql.TIMEOUT_INFINITY (%s) ' ..
15711591
'do not supported'):format(tostring(TIMEOUT_INFINITY)))
1592+
check(enable_mutations, 'enable_mutations', 'boolean')
15721593

15731594
local models, service_fields_defaults = compile_schemas(schemas,
15741595
service_fields)
@@ -1598,7 +1619,8 @@ function accessor_general.new(opts, funcs)
15981619
settings = {
15991620
resulting_object_cnt_max = resulting_object_cnt_max,
16001621
fetched_object_cnt_max = fetched_object_cnt_max,
1601-
timeout_ms = timeout_ms
1622+
timeout_ms = timeout_ms,
1623+
enable_mutations = enable_mutations,
16021624
}
16031625
}, {
16041626
__index = {

graphql/avro_helpers.lua

+10
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
--- The module us collection of helpers to simplify avro-schema related tasks.
22

33
local json = require('json')
4+
local avro_schema = require('avro_schema')
45

56
local avro_helpers = {}
67

@@ -71,4 +72,13 @@ function avro_helpers.make_avro_type_nullable(avro, opts)
7172
error("avro should be a string or a table, got " .. value_type)
7273
end
7374

75+
--- XXX
76+
function avro_helpers.major_avro_schema_version()
77+
local ok, handle = avro_schema.create('boolean')
78+
assert(ok, tostring(handle))
79+
local ok, model = avro_schema.compile(handle)
80+
assert(ok, tostring(model))
81+
return model.get_types == nil and 2 or 3
82+
end
83+
7484
return avro_helpers

graphql/tarantool_graphql.lua

+2
Original file line numberDiff line numberDiff line change
@@ -1655,6 +1655,7 @@ local function create_default_accessor(cfg)
16551655
resulting_object_cnt_max = cfg.resulting_object_cnt_max,
16561656
fetched_object_cnt_max = cfg.fetched_object_cnt_max,
16571657
timeout_ms = cfg.timeout_ms,
1658+
enable_mutations = cfg.enable_mutations,
16581659
}, cfg.accessor_funcs)
16591660
end
16601661

@@ -1668,6 +1669,7 @@ local function create_default_accessor(cfg)
16681669
resulting_object_cnt_max = cfg.resulting_object_cnt_max,
16691670
fetched_object_cnt_max = cfg.fetched_object_cnt_max,
16701671
timeout_ms = cfg.timeout_ms,
1672+
enable_mutations = cfg.enable_mutations,
16711673
}, cfg.accessor_funcs);
16721674
end
16731675
end

test/common/mutation.test.lua

+49-3
Original file line numberDiff line numberDiff line change
@@ -787,8 +787,54 @@ local function run_queries(gql_wrapper, virtbox, meta)
787787
assert(test:check(), 'check plan')
788788
end
789789

790-
test_utils.run_testdata(testdata, {
791-
run_queries = run_queries,
792-
})
790+
-- Mutations are disabled for avro-schema-2* by default, but can be enabled by
791+
-- the option.
792+
local function run_queries_avro_schema_2(test, enable_mutations, gql_wrapper,
793+
virtbox, meta)
794+
local mutation_insert = [[
795+
mutation insert_user($user: user_collection_insert) {
796+
user_collection(insert: $user) {
797+
user_id
798+
first_name
799+
last_name
800+
}
801+
}
802+
]]
803+
local ok, err = pcall(gql_wrapper.compile, gql_wrapper, mutation_insert)
804+
805+
if enable_mutations then
806+
test:ok(ok, 'mutations are enabled with the enable_mutations flag')
807+
else
808+
local err_exp = 'Variable specifies unknown type ' ..
809+
'"user_collection_insert"'
810+
test:is_deeply({ok, test_utils.strip_error(err)}, {false, err_exp},
811+
'mutations are forbidden for avro-schema-2*')
812+
end
813+
end
814+
815+
if test_utils.major_avro_schema_version() == 3 then
816+
test_utils.run_testdata(testdata, {
817+
run_queries = run_queries,
818+
})
819+
else
820+
local test = tap.test('mutation')
821+
test:plan(2)
822+
local function workload(_, shard)
823+
local virtbox = shard or box.space
824+
local meta = testdata.meta or testdata.get_test_metadata()
825+
testdata.fill_test_data(virtbox, meta)
826+
-- test mutations are disabled on avro-schema-2* by default
827+
local gql_wrapper = test_utils.graphql_from_testdata(testdata, shard)
828+
run_queries_avro_schema_2(test, false, gql_wrapper, virtbox, meta)
829+
-- test mutations can be enabled on avro-schema-2* by the option
830+
local gql_wrapper = test_utils.graphql_from_testdata(testdata, shard,
831+
{enable_mutations = true})
832+
run_queries_avro_schema_2(test, true, gql_wrapper, virtbox, meta)
833+
end
834+
test_utils.run_testdata(testdata, {
835+
workload = workload,
836+
})
837+
assert(test:check(), 'check plan')
838+
end
793839

794840
os.exit()

test/utils.lua

+19-8
Original file line numberDiff line numberDiff line change
@@ -64,6 +64,10 @@ local function get_model(meta, collection_name)
6464
return model
6565
end
6666

67+
function utils.clear_models_cache()
68+
models_cache = nil
69+
end
70+
6771
function utils.flatten_object(meta, collection_name, object,
6872
service_field_values)
6973
local model = get_model(meta, collection_name)
@@ -121,6 +125,9 @@ end
121125
function utils.run_testdata(testdata, opts)
122126
local opts = opts or {}
123127
local run_queries = opts.run_queries or testdata.run_queries
128+
-- custom workload for, say, test different options on several graphql
129+
-- instances
130+
local workload = opts.workload or nil
124131

125132
-- allow to run under tarantool on 'space' configuration w/o test-run
126133
local conf_name = test_run and test_run:get_cfg('conf') or 'space'
@@ -130,14 +137,18 @@ function utils.run_testdata(testdata, opts)
130137
init_function = testdata.init_spaces,
131138
init_function_params = {utils.major_avro_schema_version()},
132139
cleanup_function = testdata.drop_spaces,
133-
workload = function(_, shard)
134-
local virtbox = shard or box.space
135-
local meta = testdata.meta or testdata.get_test_metadata()
136-
testdata.fill_test_data(virtbox, meta)
137-
local gql_wrapper = utils.graphql_from_testdata(testdata, shard,
138-
opts.graphql_opts)
139-
run_queries(gql_wrapper, virtbox, meta)
140-
models_cache = nil -- clear models cache
140+
workload = function(conf_name, shard)
141+
if workload then
142+
workload(conf_name, shard)
143+
else
144+
local virtbox = shard or box.space
145+
local meta = testdata.meta or testdata.get_test_metadata()
146+
testdata.fill_test_data(virtbox, meta)
147+
local gql_wrapper = utils.graphql_from_testdata(testdata, shard,
148+
opts.graphql_opts)
149+
run_queries(gql_wrapper, virtbox, meta)
150+
end
151+
utils.clear_models_cache()
141152
end,
142153
servers = {'shard1', 'shard2', 'shard3', 'shard4'},
143154
use_tcp = false,

0 commit comments

Comments
 (0)