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

Commit 93a2b59

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

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
@@ -1403,29 +1403,23 @@ end
14031403
--- Provided `funcs` argument determines certain functions for retrieving
14041404
--- tuples.
14051405
---
1406-
--- @tparam table opts `schemas`, `collections`, `service_fields`, `indexes` and
1407-
--- `collection_use_tomap` ({[collection_name] = whether objects in collection
1408-
--- collection_name intended to be unflattened using tuple:tomap({names_only = true})
1409-
--- method instead of compiled_avro_schema.unflatten(tuple), ...})
1410-
--- to give the data accessor all needed meta-information re data; the format is
1411-
--- shown below; additional attributes `resulting_object_cnt_max` and
1412-
--- `fetched_object_cnt_max` are optional positive numbers which help to control
1413-
--- query behaviour in case it requires more resources than expected _(default
1414-
--- value is 10,000)_; `timeout_ms` _(default is 1000)_
1415-
---
1416-
--- @tparam table funcs set of functions:
1417-
---
1418-
--- * `is_collection_exists`,
1419-
--- * `get_index`,
1420-
--- * `get_primary_index`,
1421-
--- * `unflatten_tuple`,
1422-
--- * `flatten_object`,
1423-
--- * `insert_tuple`.
1424-
---
1425-
--- They allows this abstract data accessor behaves in the certain way (say,
1426-
--- like space data accessor or shard data accessor); consider the
1427-
--- `accessor_space` and the `accessor_shard` modules documentation for these
1428-
--- functions description.
1406+
--- @tparam table opts set of options:
1407+
---
1408+
--- * `schemas`,
1409+
--- * `collections`,
1410+
--- * `service_fields`,
1411+
--- * `indexes`,
1412+
--- * `collection_use_tomap`: ({[collection_name] = whether objects in
1413+
--- collection `collection_name` intended to be unflattened using
1414+
--- `tuple:tomap({names_only = true}` method instead of
1415+
--- `compiled_avro_schema.unflatten(tuple), ...}`),
1416+
--- * `resulting_object_cnt_max` and `fetched_object_cnt_max` are optional
1417+
--- positive numbers which help to control query behaviour in case it
1418+
--- requires more resources than expected _(default value is 10,000 for
1419+
--- both)_,
1420+
--- * `timeout_ms` _(default is 1000)_,
1421+
--- * `enable_mutations`: boolean flag _(default is `false` for avro-schema-2*
1422+
--- and `true` for avro-schema-3*)_.
14291423
---
14301424
--- For examples of `opts.schemas` and `opts.collections` consider the
14311425
--- @{tarantool_graphql.new} function description.
@@ -1452,6 +1446,20 @@ end
14521446
--- ...
14531447
--- }
14541448
---
1449+
--- @tparam table funcs set of functions:
1450+
---
1451+
--- * `is_collection_exists`,
1452+
--- * `get_index`,
1453+
--- * `get_primary_index`,
1454+
--- * `unflatten_tuple`,
1455+
--- * `flatten_object`,
1456+
--- * `insert_tuple`.
1457+
---
1458+
--- They allows this abstract data accessor behaves in the certain way (say,
1459+
--- like space data accessor or shard data accessor); consider the
1460+
--- `accessor_space` and the `accessor_shard` modules documentation for these
1461+
--- functions description.
1462+
---
14551463
--- @treturn table data accessor instance, a table with the two methods
14561464
--- (`select` and `arguments`) as described in the @{tarantool_graphql.new}
14571465
--- function description.
@@ -1471,6 +1479,14 @@ function accessor_general.new(opts, funcs)
14711479
DEF_FETCHED_OBJECT_CNT_MAX
14721480
-- TODO: move this setting to `tgql.compile` after #59
14731481
local timeout_ms = opts.timeout_ms or DEF_TIMEOUT_MS
1482+
-- Mutations are disabled for avro-schema-2*, because it can work
1483+
-- incorrectly for schemas with nullable types.
1484+
local enable_mutations
1485+
if opts.enable_mutations == nil then
1486+
enable_mutations = avro_helpers.major_avro_schema_version() == 3
1487+
else
1488+
enable_mutations = opts.enable_mutations
1489+
end
14741490

14751491
assert(type(schemas) == 'table',
14761492
'schemas must be a table, got ' .. type(schemas))
@@ -1492,6 +1508,7 @@ function accessor_general.new(opts, funcs)
14921508
assert(timeout_ms <= TIMEOUT_INFINITY,
14931509
('timeouts more then graphql.TIMEOUT_INFINITY (%s) ' ..
14941510
'do not supported'):format(tostring(TIMEOUT_INFINITY)))
1511+
check(enable_mutations, 'enable_mutations', 'boolean')
14951512

14961513
local models, service_fields_defaults = compile_schemas(schemas,
14971514
service_fields)
@@ -1521,7 +1538,8 @@ function accessor_general.new(opts, funcs)
15211538
settings = {
15221539
resulting_object_cnt_max = resulting_object_cnt_max,
15231540
fetched_object_cnt_max = fetched_object_cnt_max,
1524-
timeout_ms = timeout_ms
1541+
timeout_ms = timeout_ms,
1542+
enable_mutations = enable_mutations,
15251543
}
15261544
}, {
15271545
__index = {
@@ -1567,6 +1585,10 @@ function accessor_general.new(opts, funcs)
15671585
}
15681586
end,
15691587
extra_args = function(self, collection_name)
1588+
if not self.settings.enable_mutations then
1589+
return {}, {}
1590+
end
1591+
15701592
local collection = self.collections[collection_name]
15711593
local schema_name = collection.schema_name
15721594

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
@@ -1624,6 +1624,7 @@ local function create_default_accessor(cfg)
16241624
resulting_object_cnt_max = cfg.resulting_object_cnt_max,
16251625
fetched_object_cnt_max = cfg.fetched_object_cnt_max,
16261626
timeout_ms = cfg.timeout_ms,
1627+
enable_mutations = cfg.enable_mutations,
16271628
}, cfg.accessor_funcs)
16281629
end
16291630

@@ -1637,6 +1638,7 @@ local function create_default_accessor(cfg)
16371638
resulting_object_cnt_max = cfg.resulting_object_cnt_max,
16381639
fetched_object_cnt_max = cfg.fetched_object_cnt_max,
16391640
timeout_ms = cfg.timeout_ms,
1641+
enable_mutations = cfg.enable_mutations,
16401642
}, cfg.accessor_funcs);
16411643
end
16421644
end

test/common/mutation.test.lua

+49-3
Original file line numberDiff line numberDiff line change
@@ -727,8 +727,54 @@ local function run_queries(gql_wrapper, virtbox, meta)
727727
assert(test:check(), 'check plan')
728728
end
729729

730-
test_utils.run_testdata(testdata, {
731-
run_queries = run_queries,
732-
})
730+
-- Mutations are disabled for avro-schema-2* by default, but can be enabled by
731+
-- the option.
732+
local function run_queries_avro_schema_2(test, enable_mutations, gql_wrapper,
733+
virtbox, meta)
734+
local mutation_insert = [[
735+
mutation insert_user($user: user_collection_insert) {
736+
user_collection(insert: $user) {
737+
user_id
738+
first_name
739+
last_name
740+
}
741+
}
742+
]]
743+
local ok, err = pcall(gql_wrapper.compile, gql_wrapper, mutation_insert)
744+
745+
if enable_mutations then
746+
test:ok(ok, 'mutations are enabled with the enable_mutations flag')
747+
else
748+
local err_exp = 'Variable specifies unknown type ' ..
749+
'"user_collection_insert"'
750+
test:is_deeply({ok, test_utils.strip_error(err)}, {false, err_exp},
751+
'mutations are forbidden for avro-schema-2*')
752+
end
753+
end
754+
755+
if test_utils.major_avro_schema_version() == 3 then
756+
test_utils.run_testdata(testdata, {
757+
run_queries = run_queries,
758+
})
759+
else
760+
local test = tap.test('mutation')
761+
test:plan(2)
762+
local function workload(_, shard)
763+
local virtbox = shard or box.space
764+
local meta = testdata.meta or testdata.get_test_metadata()
765+
testdata.fill_test_data(virtbox, meta)
766+
-- test mutations are disabled on avro-schema-2* by default
767+
local gql_wrapper = test_utils.graphql_from_testdata(testdata, shard)
768+
run_queries_avro_schema_2(test, false, gql_wrapper, virtbox, meta)
769+
-- test mutations can be enabled on avro-schema-2* by the option
770+
local gql_wrapper = test_utils.graphql_from_testdata(testdata, shard,
771+
{enable_mutations = true})
772+
run_queries_avro_schema_2(test, true, gql_wrapper, virtbox, meta)
773+
end
774+
test_utils.run_testdata(testdata, {
775+
workload = workload,
776+
})
777+
assert(test:check(), 'check plan')
778+
end
733779

734780
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)