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

Commit 1a131ee

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

File tree

6 files changed

+133
-35
lines changed

6 files changed

+133
-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
@@ -1458,6 +1458,10 @@ end
14581458
--- ...
14591459
--- }
14601460
local function extra_args(self, collection_name)
1461+
if not self.settings.enable_mutations then
1462+
return {}, {}
1463+
end
1464+
14611465
local collection = self.collections[collection_name]
14621466
local schema_name = collection.schema_name
14631467

@@ -1519,29 +1523,23 @@ end
15191523
--- Provided `funcs` argument determines certain functions for retrieving
15201524
--- tuples.
15211525
---
1522-
--- @tparam table opts `schemas`, `collections`, `service_fields`, `indexes` and
1523-
--- `collection_use_tomap` ({[collection_name] = whether objects in collection
1524-
--- collection_name intended to be unflattened using tuple:tomap({names_only = true})
1525-
--- method instead of compiled_avro_schema.unflatten(tuple), ...})
1526-
--- to give the data accessor all needed meta-information re data; the format is
1527-
--- shown below; additional attributes `resulting_object_cnt_max` and
1528-
--- `fetched_object_cnt_max` are optional positive numbers which help to control
1529-
--- query behaviour in case it requires more resources than expected _(default
1530-
--- value is 10,000)_; `timeout_ms` _(default is 1000)_
1531-
---
1532-
--- @tparam table funcs set of functions:
1533-
---
1534-
--- * `is_collection_exists`,
1535-
--- * `get_index`,
1536-
--- * `get_primary_index`,
1537-
--- * `unflatten_tuple`,
1538-
--- * `flatten_object`,
1539-
--- * `insert_tuple`.
1540-
---
1541-
--- They allows this abstract data accessor behaves in the certain way (say,
1542-
--- like space data accessor or shard data accessor); consider the
1543-
--- `accessor_space` and the `accessor_shard` modules documentation for these
1544-
--- functions description.
1526+
--- @tparam table opts set of options:
1527+
---
1528+
--- * `schemas`,
1529+
--- * `collections`,
1530+
--- * `service_fields`,
1531+
--- * `indexes`,
1532+
--- * `collection_use_tomap`: ({[collection_name] = whether objects in
1533+
--- collection `collection_name` intended to be unflattened using
1534+
--- `tuple:tomap({names_only = true}` method instead of
1535+
--- `compiled_avro_schema.unflatten(tuple), ...}`),
1536+
--- * `resulting_object_cnt_max` and `fetched_object_cnt_max` are optional
1537+
--- positive numbers which help to control query behaviour in case it
1538+
--- requires more resources than expected _(default value is 10,000 for
1539+
--- both)_,
1540+
--- * `timeout_ms` _(default is 1000)_,
1541+
--- * `enable_mutations`: boolean flag _(default is `false` for avro-schema-2*
1542+
--- and `true` for avro-schema-3*)_.
15451543
---
15461544
--- For examples of `opts.schemas` and `opts.collections` consider the
15471545
--- @{tarantool_graphql.new} function description.
@@ -1568,6 +1566,20 @@ end
15681566
--- ...
15691567
--- }
15701568
---
1569+
--- @tparam table funcs set of functions:
1570+
---
1571+
--- * `is_collection_exists`,
1572+
--- * `get_index`,
1573+
--- * `get_primary_index`,
1574+
--- * `unflatten_tuple`,
1575+
--- * `flatten_object`,
1576+
--- * `insert_tuple`.
1577+
---
1578+
--- They allows this abstract data accessor behaves in the certain way (say,
1579+
--- like space data accessor or shard data accessor); consider the
1580+
--- `accessor_space` and the `accessor_shard` modules documentation for these
1581+
--- functions description.
1582+
---
15711583
--- @treturn table data accessor instance, a table with the two methods
15721584
--- (`select` and `arguments`) as described in the @{tarantool_graphql.new}
15731585
--- function description.
@@ -1587,6 +1599,14 @@ function accessor_general.new(opts, funcs)
15871599
DEF_FETCHED_OBJECT_CNT_MAX
15881600
-- TODO: move this setting to `tgql.compile` after #59
15891601
local timeout_ms = opts.timeout_ms or DEF_TIMEOUT_MS
1602+
-- Mutations are disabled for avro-schema-2*, because it can work
1603+
-- incorrectly for schemas with nullable types.
1604+
local enable_mutations
1605+
if opts.enable_mutations == nil then
1606+
enable_mutations = avro_helpers.major_avro_schema_version() == 3
1607+
else
1608+
enable_mutations = opts.enable_mutations
1609+
end
15901610

15911611
assert(type(schemas) == 'table',
15921612
'schemas must be a table, got ' .. type(schemas))
@@ -1608,6 +1628,7 @@ function accessor_general.new(opts, funcs)
16081628
assert(timeout_ms <= TIMEOUT_INFINITY,
16091629
('timeouts more then graphql.TIMEOUT_INFINITY (%s) ' ..
16101630
'do not supported'):format(tostring(TIMEOUT_INFINITY)))
1631+
check(enable_mutations, 'enable_mutations', 'boolean')
16111632

16121633
local models, service_fields_defaults = compile_schemas(schemas,
16131634
service_fields)
@@ -1637,7 +1658,8 @@ function accessor_general.new(opts, funcs)
16371658
settings = {
16381659
resulting_object_cnt_max = resulting_object_cnt_max,
16391660
fetched_object_cnt_max = fetched_object_cnt_max,
1640-
timeout_ms = timeout_ms
1661+
timeout_ms = timeout_ms,
1662+
enable_mutations = enable_mutations,
16411663
}
16421664
}, {
16431665
__index = {

graphql/avro_helpers.lua

+12
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,15 @@ 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+
--- Determines major version of the avro-schema module in use.
76+
---
77+
--- @treturn number 2 or 3
78+
function avro_helpers.major_avro_schema_version()
79+
local ok, handle = avro_schema.create('boolean')
80+
assert(ok, tostring(handle))
81+
local ok, model = avro_schema.compile(handle)
82+
assert(ok, tostring(model))
83+
return model.get_types == nil and 2 or 3
84+
end
85+
7486
return avro_helpers

graphql/tarantool_graphql.lua

+2
Original file line numberDiff line numberDiff line change
@@ -1675,6 +1675,7 @@ local function create_default_accessor(cfg)
16751675
resulting_object_cnt_max = cfg.resulting_object_cnt_max,
16761676
fetched_object_cnt_max = cfg.fetched_object_cnt_max,
16771677
timeout_ms = cfg.timeout_ms,
1678+
enable_mutations = cfg.enable_mutations,
16781679
}, cfg.accessor_funcs)
16791680
end
16801681

@@ -1688,6 +1689,7 @@ local function create_default_accessor(cfg)
16881689
resulting_object_cnt_max = cfg.resulting_object_cnt_max,
16891690
fetched_object_cnt_max = cfg.fetched_object_cnt_max,
16901691
timeout_ms = cfg.timeout_ms,
1692+
enable_mutations = cfg.enable_mutations,
16911693
}, cfg.accessor_funcs)
16921694
end
16931695
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)