diff --git a/README.md b/README.md index 0ef7cfa..e1f2922 100644 --- a/README.md +++ b/README.md @@ -97,7 +97,8 @@ make test * For use: tarantool, lulpeg, >=tarantool/shard-1.1-91-gfa88bf8 (optional), tarantool/avro-schema. -* For test (additionally to 'for use'): python 2.7, virtualenv, luacheck. +* For test (additionally to 'for use'): python 2.7, virtualenv, luacheck, + >=tarantool/shard-1.1-92-gec1a27e. * For building apidoc (additionally to 'for use'): ldoc. ## License diff --git a/graphql/accessor_general.lua b/graphql/accessor_general.lua index e1f8c86..32b6e11 100644 --- a/graphql/accessor_general.lua +++ b/graphql/accessor_general.lua @@ -103,7 +103,7 @@ end --- Get a key to lookup index by `lookup_index_name` (part of `index_cache`). --- --- @tparam table filter filter for objects, its keys (names of fields) will ---- form the result +--- form the result of the function --- --- @treturn string `name_list_str` (key for lookup by `lookup_index_name`) local function filter_names_fingerprint(filter) @@ -123,14 +123,91 @@ local function filter_names_fingerprint(filter) return name_list_str end +--- Get an index using parts tree built by @{build_index_parts_tree}. +--- +--- @tparam table node root of the prefix tree for certain collection +--- +--- @tparam table filter map of key-value to filter objects against +--- +--- @treturn string `index_name` or `nil` is found index +--- +--- @treturn number `max_branch_len` is a number of index parts will be used at +--- lookup plus 1 (because it calculated artificial root node as well as other +--- nodes) +--- +--- Complexity +--- ---------- +--- +--- In short: O(SIZE(filter)^2 * COUNT(index parts for all indexes)). +--- +--- Say we have N fields in filter (N = SIZE(filter), M indexes and K index +--- parts at max ((M * K) and COUNT(index parts for all indexes) both are are +--- upside limits of nodes count in the tree). We look for successors for +--- each filter item (<= N items) in each of the tree node (<= M * K nodes), +--- so have O(I * N * (M * K)) of somewhat we call 'iteration' of I +--- complexity. Most heavy operation within an iteraton is table.copy(), we +--- can assume it has O(N) complexity. So we have overall complexity O(N^2 * +--- (M * K)). +--- +--- We can consider worst case scenario when any node has any of filter keys as +--- a successor. In this case nodes count is not real constraint for recursion. +--- In such case we can calculate complexity as iteration of weight I +--- (calculated above as O(N^2)) and iteration count as permutations of N +--- filter items (N!). In such case we'll have O(N^2 * N!) or O(N^(3/2) * N^N) +--- (Stirling's approximation). +--- +--- Expectations +--- ------------ +--- +--- We expect typical filter size as 1 or 2 and tree depth (excluding +--- artificial root node) of the same order. So despite horrible complexity +--- estimation it expected to be non-so-heavy. Our guess is that it worth to +--- try hard to find best index before a large request. +--- +--- Future optimizations +--- -------------------- +--- +--- * replace table.copy() with something more light: maybe 'closed set' of +-- filter items or {remove filter[k], invoke the function, add +--- back filter[k]} (but it needed to be done in such way that will not +--- invalidate pairs()); +--- * cache index name btw block requests of the same collection request (when +--- we'll have block executor) and maybe even btw different requests with the +-- same filter keys. +local function get_best_matched_index(node, filter) + local index_name = (node.index_names or {})[1] + local max_branch_len = 1 + + -- optimization: don't run the loop below if there are no successors of the + -- current node + if node.successors == nil then + return index_name, 1 + end + + for k, v in pairs(filter) do + local successor_node = (node.successors or {})[k] + if successor_node ~= nil then + local new_filter = table.copy(filter) + new_filter[k] = nil + local branch_index_name, branch_len = + get_best_matched_index(successor_node, new_filter) + branch_len = branch_len + 1 + if branch_index_name ~= nil and branch_len > max_branch_len then + index_name = branch_index_name + max_branch_len = branch_len + end + end + end + + return index_name, max_branch_len +end + -- XXX: raw idea: we can store field-to-field_no mapping when creating -- `lookup_index_name` to faster form the value_list --- Flatten filter values (transform to a list) against specific index to --- passing it to index:pairs(). --- ---- Only full keys are supported for a compound index for now. ---- --- @tparam table self the data accessor --- --- @tparam table filter filter for objects, its values will ordered to form @@ -146,6 +223,9 @@ end --- passed index --- --- @treturn table `value_list` the value to pass to index:pairs() +--- +--- @treturn table `new_filter` the `filter` value w/o values extracted to +--- `value_list` local function flatten_filter(self, filter, collection_name, index_name) assert(type(self) == 'table', 'self must be a table, got ' .. type(self)) @@ -155,6 +235,7 @@ local function flatten_filter(self, filter, collection_name, index_name) 'index_name must be a string, got ' .. type(index_name)) local value_list = {} + local new_filter = table.copy(filter) -- fill value_list local index_meta = self.indexes[collection_name][index_name] @@ -165,6 +246,7 @@ local function flatten_filter(self, filter, collection_name, index_name) local value = filter[field_name] if value == nil then break end value_list[#value_list + 1] = value + new_filter[field_name] = nil end -- check for correctness: non-empty value_list @@ -174,26 +256,11 @@ local function flatten_filter(self, filter, collection_name, index_name) json.encode(filter), index_name)) end - -- check for correctness: all filter fields are used - local count = 0 - for k, v in pairs(filter) do - count = count + 1 - end - if count ~= #value_list then -- avoid extra json.encode() - assert(count ~= #value_list, - ('filter items count does not match index fields count: ' .. - 'filter: %s, index_name: %s'):format(json.encode(filter), - index_name)) - end - - local full_match = #value_list == #index_meta.fields - return full_match, value_list + local full_match = #value_list == #index_meta.fields and + next(new_filter) == nil + return full_match, value_list, new_filter end --- XXX: support partial match for primary/secondary indexes and support to skip --- fields to get an index (full_match must be false in the case because --- returned items will be additionally filtered after unflatten). - --- Choose an index for lookup tuple(s) by a 'filter'. The filter holds fields --- values of object(s) we want to find. It uses prebuilt `lookup_index_name` --- table representing available indexes, which created by the @@ -232,9 +299,12 @@ end --- --- @treturn string `index_name` is name of the found index or nil --- ---- @treturn table `value_list` is values list from the `filter` argument ---- ordered in the such way that can be passed to the found index (has some ---- meaning only when `index_name ~= nil`) +--- @treturn table `new_filter` is the filter value w/o values extracted into +--- `value_list` +--- +--- @treturn table `value_list` (optional) is values list from the `filter` +--- argument ordered in the such way that it can be passed to the found index +-- (has some meaning only when `index_name ~= nil`) --- --- @treturn table `pivot` (optional) an offset argument represented depending --- of a case: whether we'll lookup for the offset by an index; it is either @@ -261,6 +331,10 @@ local get_index_name = function(self, collection_name, from, filter, args) assert(type(lookup_index_name) == 'table', 'lookup_index_name must be a table, got ' .. type(lookup_index_name)) + local parts_tree = index_cache.parts_tree + assert(type(parts_tree) == 'table', + 'parts_tree must be a table, got ' .. type(parts_tree)) + local connection_indexes = index_cache.connection_indexes assert(type(connection_indexes) == 'table', 'connection_indexes must be a table, got ' .. type(connection_indexes)) @@ -278,6 +352,7 @@ local get_index_name = function(self, collection_name, from, filter, args) assert(connection_type ~= nil, 'connection_type must not be nil') local full_match = connection_type == '1:1' and next(filter) == nil local value_list = from.destination_args_values + local new_filter = filter local pivot if args.offset ~= nil then @@ -298,21 +373,22 @@ local get_index_name = function(self, collection_name, from, filter, args) pivot = {filter = pivot_filter} end - return full_match, index_name, value_list, pivot + return full_match, index_name, new_filter, value_list, pivot end -- The 'fast offset' case. Here we fetch top-level objects starting from -- passed offset. Select will be performed by the primary index and -- corresponding offset in `pivot.value_list`, then the result will be - -- postprocessed using `filter`, if necessary. + -- postprocessed using `new_filter`, if necessary. if args.offset ~= nil then local index_name, index_meta = get_primary_index_meta(self, collection_name) local full_match local pivot_value_list + local new_filter = filter if type(args.offset) == 'table' then - full_match, pivot_value_list = flatten_filter(self, args.offset, - collection_name, index_name) + full_match, pivot_value_list, new_filter = flatten_filter(self, + args.offset, collection_name, index_name) assert(full_match == true, 'offset by a partial key is forbidden') else assert(#index_meta.fields == 1, @@ -322,22 +398,34 @@ local get_index_name = function(self, collection_name, from, filter, args) end local pivot = {value_list = pivot_value_list} full_match = full_match and next(filter) == nil - return full_match, index_name, filter, pivot + return full_match, index_name, new_filter, nil, pivot end -- The 'no offset' case. Here we fetch top-level object either by found -- index or using full scan (if the index was not found). + + -- try to find full index local name_list_str = filter_names_fingerprint(filter) assert(lookup_index_name[collection_name] ~= nil, ('cannot find any index for collection "%s"'):format(collection_name)) local index_name = lookup_index_name[collection_name][name_list_str] local full_match = false local value_list = nil + local new_filter = filter + + -- try to find partial index + if index_name == nil then + local root = parts_tree[collection_name] + index_name = get_best_matched_index(root, filter) + end + + -- fill full_match and value_list appropriatelly if index_name ~= nil then - full_match, value_list = flatten_filter(self, filter, collection_name, - index_name) + full_match, value_list, new_filter = flatten_filter(self, filter, + collection_name, index_name) end - return full_match, index_name, value_list + + return full_match, index_name, new_filter, value_list end --- Build `lookup_index_name` table (part of `index_cache`) to use in the @@ -404,6 +492,67 @@ local function build_lookup_index_name(indexes) return lookup_index_name end +--- Build `parts_tree` to use in @{get_index_name} for lookup best matching +--- index. +--- +--- @tparam table indexes indexes metainformation as defined in the @{new} +--- function +--- +--- Schetch example: +--- +--- * collection_1: +--- * index 1 parts: foo, bar, baz; +--- * index 2 parts: foo, abc; +--- * index 3 parts: abc, efg, hij; +-- * index 4 parts: abc. +--- +--- Resulting table of prefix trees (contains one field for collection_1): +--- +--- ``` +--- * collection_1: +--- \ +--- + --> root node --> foo --> bar --> baz ~~> index 1 +--- \ \ +--- \ + --> abc ~~> index 2 +--- \ +--- + ------> abc --> efg --> hij ~~ index 3 +--- \ +--- + ~~> index 4 +--- ``` +--- +--- @treturn table `roots` resulting table of prefix trees +--- +--- * `roots` is a table which maps `collection names` to `root nodes` of +--- prefix trees; +--- * 'collection name` is a string (name of a collection); +--- * `root node` is a table with `successors` field; +--- * `successors` field value is a map from `index part` to `non-root node`; +--- * `index part` is a string (name of corresponding field in an object); +--- * `non-root node` is a table with `index_names` field and optional +--- `successors` field; +--- * `index_names` field value is a list of `index name`; +--- * `index name` is a string (name of an index). +local function build_index_parts_tree(indexes) + local roots = {} + + for collection_name, indexes_meta in pairs(indexes) do + local root = {} + roots[collection_name] = root + for index_name, index_meta in pairs(indexes_meta) do + local cur = root + for _, field in ipairs(index_meta.fields) do + cur.successors = cur.successors or {} + cur.successors[field] = cur.successors[field] or {} + cur = cur.successors[field] + cur.index_names = cur.index_names or {} + cur.index_names[#cur.index_names + 1] = index_name + end + end + end + + return roots +end + --- Build `connection_indexes` table (part of `index_cache`) to use in the --- @{get_index_name} function. --- @@ -493,6 +642,7 @@ end local function build_index_cache(indexes, collections) return { lookup_index_name = build_lookup_index_name(indexes), + parts_tree = build_index_parts_tree(indexes), connection_indexes = build_connection_indexes(indexes, collections), } end @@ -683,13 +833,14 @@ local function select_internal(self, collection_name, from, filter, args, extra) assert(collection ~= nil, ('cannot find the collection "%s"'):format( collection_name)) - - -- search for suitable index - local full_match, index_name, index_value, pivot = get_index_name( - self, collection_name, from, filter, args) assert(self.funcs.is_collection_exists(collection_name), ('cannot find collection "%s"'):format(collection_name)) - local index = self.funcs.get_index(collection_name, index_name) + + -- search for suitable index + local full_match, index_name, filter, index_value, pivot = get_index_name( + self, collection_name, from, filter, args) -- we redefine filter here + local index = index_name ~= nil and + self.funcs.get_index(collection_name, index_name) or nil if from.collection_name ~= 'Query' then -- allow fullscan only for a top-level object assert(index ~= nil, diff --git a/test-run b/test-run index ff5fb4f..6d86934 160000 --- a/test-run +++ b/test-run @@ -1 +1 @@ -Subproject commit ff5fb4f3016e150ea62d2dcaffcfce645a14b3f8 +Subproject commit 6d86934b6aec96db9636846b9cc7e339e8d52cf0 diff --git a/test/common/lua/multirunner.lua b/test/common/lua/multirunner.lua index 9e5f97d..5efb876 100755 --- a/test/common/lua/multirunner.lua +++ b/test/common/lua/multirunner.lua @@ -30,13 +30,6 @@ end local function shard_cleanup(test_run, servers) test_run:drop_cluster(servers) - -- crutch!! - -- test_run.lua do not delete servers - -- todo: should be removed after #83 is fixed in test-run - local drop_cluster_cmd3 = 'delete server %s' - for _, name in ipairs(servers) do - test_run:cmd(drop_cluster_cmd3:format(name)) - end end local function for_each_server(shard, func) diff --git a/test/local/space_compound_index.result b/test/local/space_compound_index.result index 789eda1..3fad85b 100644 --- a/test/local/space_compound_index.result +++ b/test/local/space_compound_index.result @@ -1,3 +1,21 @@ +RUN 1_1 {{{ +QUERY + query users($user_str: String, $user_num: Long, + $first_name: String) { + user_collection(user_str: $user_str, user_num: $user_num + first_name: $first_name) { + user_str + user_num + last_name + first_name + } + } +VARIABLES +--- +user_num: 12 +user_str: user_str_b +... + RESULT --- user_collection: @@ -7,6 +25,51 @@ user_collection: user_num: 12 ... +}}} + +RUN 1_2 {{{ +QUERY + query users($user_str: String, $user_num: Long, + $first_name: String) { + user_collection(user_str: $user_str, user_num: $user_num + first_name: $first_name) { + user_str + user_num + last_name + first_name + } + } +VARIABLES +--- +user_str: user_str_b +first_name: non-existent +user_num: 12 +... + +RESULT +--- +user_collection: [] +... + +}}} + +RUN 1_3 {{{ +QUERY + query users($user_str: String, $user_num: Long, + $first_name: String) { + user_collection(user_str: $user_str, user_num: $user_num + first_name: $first_name) { + user_str + user_num + last_name + first_name + } + } +VARIABLES +--- +user_num: 12 +... + RESULT --- user_collection: @@ -32,6 +95,183 @@ user_collection: user_num: 12 ... +}}} + +RUN 1_4 {{{ +QUERY + query users($user_str: String, $user_num: Long, + $first_name: String) { + user_collection(user_str: $user_str, user_num: $user_num + first_name: $first_name) { + user_str + user_num + last_name + first_name + } + } +VARIABLES +--- +user_str: user_str_b +... + +RESULT +--- +user_collection: +- last_name: last name b + user_str: user_str_b + first_name: first name b + user_num: 1 +- last_name: last name b + user_str: user_str_b + first_name: first name b + user_num: 2 +- last_name: last name b + user_str: user_str_b + first_name: first name b + user_num: 3 +- last_name: last name b + user_str: user_str_b + first_name: first name b + user_num: 4 +- last_name: last name b + user_str: user_str_b + first_name: first name b + user_num: 5 +- last_name: last name b + user_str: user_str_b + first_name: first name b + user_num: 6 +- last_name: last name b + user_str: user_str_b + first_name: first name b + user_num: 7 +- last_name: last name b + user_str: user_str_b + first_name: first name b + user_num: 8 +- last_name: last name b + user_str: user_str_b + first_name: first name b + user_num: 9 +- last_name: last name b + user_str: user_str_b + first_name: first name b + user_num: 10 +- last_name: last name b + user_str: user_str_b + first_name: first name b + user_num: 11 +- last_name: last name b + user_str: user_str_b + first_name: first name b + user_num: 12 +- last_name: last name b + user_str: user_str_b + first_name: first name b + user_num: 13 +- last_name: last name b + user_str: user_str_b + first_name: first name b + user_num: 14 +- last_name: last name b + user_str: user_str_b + first_name: first name b + user_num: 15 +- last_name: last name b + user_str: user_str_b + first_name: first name b + user_num: 16 +- last_name: last name b + user_str: user_str_b + first_name: first name b + user_num: 17 +- last_name: last name b + user_str: user_str_b + first_name: first name b + user_num: 18 +- last_name: last name b + user_str: user_str_b + first_name: first name b + user_num: 19 +- last_name: last name b + user_str: user_str_b + first_name: first name b + user_num: 20 +... + +}}} + +RUN 1_5 {{{ +QUERY + query users($user_str: String, $user_num: Long, + $first_name: String) { + user_collection(user_str: $user_str, user_num: $user_num + first_name: $first_name) { + user_str + user_num + last_name + first_name + } + } +VARIABLES +--- +first_name: non-existent +user_num: 12 +... + +RESULT +--- +user_collection: [] +... + +}}} + +RUN 1_6 {{{ +QUERY + query users($user_str: String, $user_num: Long, + $first_name: String) { + user_collection(user_str: $user_str, user_num: $user_num + first_name: $first_name) { + user_str + user_num + last_name + first_name + } + } +VARIABLES +--- +first_name: non-existent +user_str: user_str_b +... + +RESULT +--- +user_collection: [] +... + +}}} + +RUN 2_1 {{{ +QUERY + query users($user_str: String, $user_num: Long, $description: String) { + user_collection(user_str: $user_str, user_num: $user_num) { + user_str + user_num + last_name + first_name + order_connection(description: $description) { + order_str + order_num + description + } + } + } +VARIABLES +--- +user_num: 12 +user_str: user_str_b +... + RESULT --- user_collection: @@ -72,6 +312,63 @@ user_collection: last_name: last name b ... +}}} + +RUN 2_2 {{{ +QUERY + query users($user_str: String, $user_num: Long, $description: String) { + user_collection(user_str: $user_str, user_num: $user_num) { + user_str + user_num + last_name + first_name + order_connection(description: $description) { + order_str + order_num + description + } + } + } +VARIABLES +--- +user_str: user_str_b +description: non-existent +user_num: 12 +... + +RESULT +--- +user_collection: +- order_connection: [] + user_str: user_str_b + first_name: first name b + user_num: 12 + last_name: last name b +... + +}}} + +RUN 3 {{{ +QUERY + query users($user_str: String, $user_num: Long) { + user_collection(user_str: $user_str, user_num: $user_num) { + user_str + user_num + last_name + first_name + order_str_connection { + order_str + order_num + description + } + } + } +VARIABLES +--- +user_num: 12 +user_str: user_str_b +... + RESULT --- user_collection: @@ -682,6 +979,26 @@ user_collection: description: description b ... +}}} + +RUN 4_1 {{{ +QUERY + query users($limit: Int, $offset: user_collection_offset) { + user_collection(limit: $limit, offset: $offset) { + user_str + user_num + last_name + first_name + } + } +VARIABLES +--- +offset: + user_num: 12 + user_str: user_str_b +limit: 10 +... + RESULT --- user_collection: @@ -727,7 +1044,59 @@ user_collection: user_num: 2 ... -RESULT: ok: false; err: offset by a partial key is forbidden +}}} + +RUN 4_2 {{{ +QUERY + query users($limit: Int, $offset: user_collection_offset) { + user_collection(limit: $limit, offset: $offset) { + user_str + user_num + last_name + first_name + } + } +VARIABLES +--- +offset: + user_str: user_str_b +limit: 10 +... + +RESULT +--- +ok: false +err: offset by a partial key is forbidden +... + +}}} + +RUN 5_1 {{{ +QUERY + query users($user_str: String, $user_num: Long, + $limit: Int, $offset: order_collection_offset) { + user_collection(user_str: $user_str, user_num: $user_num) { + user_str + user_num + last_name + first_name + order_connection(limit: $limit, offset: $offset) { + order_str + order_num + description + } + } + } +VARIABLES +--- +offset: + order_num: 1202 + order_str: order_str_b_2 +user_str: user_str_b +limit: 4 +user_num: 12 +... + RESULT --- user_collection: @@ -750,4 +1119,38 @@ user_collection: last_name: last name b ... -RESULT: ok: false; err: offset by a partial key is forbidden: expected "order_num" field +}}} + +RUN 5_2 {{{ +QUERY + query users($user_str: String, $user_num: Long, + $limit: Int, $offset: order_collection_offset) { + user_collection(user_str: $user_str, user_num: $user_num) { + user_str + user_num + last_name + first_name + order_connection(limit: $limit, offset: $offset) { + order_str + order_num + description + } + } + } +VARIABLES +--- +offset: + order_str: order_str_b_2 +user_str: user_str_b +limit: 4 +user_num: 12 +... + +RESULT +--- +ok: false +err: 'offset by a partial key is forbidden: expected "order_num" field' +... + +}}} + diff --git a/test/shard_no_redundancy/shard_common.result b/test/shard_no_redundancy/shard_common.result index 11768fb..b5fcacc 100644 --- a/test/shard_no_redundancy/shard_common.result +++ b/test/shard_no_redundancy/shard_common.result @@ -63,6 +63,9 @@ test_run:cmd('switch default') --- - true ... +shard.reload_schema() +--- +... -- upload test data testdata.fill_test_data(shard) --- diff --git a/test/shard_no_redundancy/shard_common.test.lua b/test/shard_no_redundancy/shard_common.test.lua index 91855c2..65a87f2 100644 --- a/test/shard_no_redundancy/shard_common.test.lua +++ b/test/shard_no_redundancy/shard_common.test.lua @@ -33,6 +33,7 @@ require('test.testdata.common_testdata').init_spaces() test_run:cmd('switch shard2') require('test.testdata.common_testdata').init_spaces() test_run:cmd('switch default') +shard.reload_schema() -- upload test data testdata.fill_test_data(shard) diff --git a/test/shard_no_redundancy/shard_compound_index.result b/test/shard_no_redundancy/shard_compound_index.result new file mode 100644 index 0000000..7c84e8a --- /dev/null +++ b/test/shard_no_redundancy/shard_compound_index.result @@ -0,0 +1,1296 @@ +env = require('test_run') +--- +... +test_run = env.new() +--- +... +shard = require('shard') +--- +... +test_run:cmd("setopt delimiter ';'") +--- +- true +... +SERVERS = {'shard1', 'shard2'}; +--- +... +init_shard(SERVERS, { + servers = { + { uri = instance_uri('1'), zone = '0' }, + { uri = instance_uri('2'), zone = '1' }, + }, + login = 'guest', + password = '', + redundancy = 1, +}, 'shard_no_redundancy'); +--- +... +test_run:cmd("setopt delimiter ''"); +--- +- true +... +fio = require('fio') +--- +... +-- require in-repo version of graphql/ sources despite current working directory +package.path = fio.abspath(debug.getinfo(1).source:match("@?(.*/)"):gsub('/./', '/'):gsub('/+$', '')) .. '/../../?.lua' .. ';' .. package.path +--- +... +graphql = require('graphql') +--- +... +testdata = require('test.testdata.compound_index_testdata') +--- +... +-- init box, upload test data and acquire metadata +-- ----------------------------------------------- +-- init box and data schema +test_run:cmd('switch shard1') +--- +- true +... +require('test.testdata.compound_index_testdata').init_spaces() +--- +... +test_run:cmd('switch shard2') +--- +- true +... +require('test.testdata.compound_index_testdata').init_spaces() +--- +... +test_run:cmd('switch default') +--- +- true +... +shard.reload_schema() +--- +... +-- upload test data +testdata.fill_test_data(shard) +--- +... +-- acquire metadata +metadata = testdata.get_test_metadata() +--- +... +schemas = metadata.schemas +--- +... +collections = metadata.collections +--- +... +service_fields = metadata.service_fields +--- +... +indexes = metadata.indexes +--- +... +-- build accessor and graphql schemas +-- ---------------------------------- +test_run:cmd("setopt delimiter ';'") +--- +- true +... +accessor = graphql.accessor_shard.new({ + schemas = schemas, + collections = collections, + service_fields = service_fields, + indexes = indexes, +}); +--- +... +gql_wrapper = graphql.new({ + schemas = schemas, + collections = collections, + accessor = accessor, +}); +--- +... +test_run:cmd("setopt delimiter ''"); +--- +- true +... +testdata.run_queries(gql_wrapper) +--- +- |+ + RUN 1_1 {{{ + QUERY + query users($user_str: String, $user_num: Long, + $first_name: String) { + user_collection(user_str: $user_str, user_num: $user_num + first_name: $first_name) { + user_str + user_num + last_name + first_name + } + } + VARIABLES + --- + user_num: 12 + user_str: user_str_b + ... + + RESULT + --- + user_collection: + - last_name: last name b + user_str: user_str_b + first_name: first name b + user_num: 12 + ... + + }}} + + RUN 1_2 {{{ + QUERY + query users($user_str: String, $user_num: Long, + $first_name: String) { + user_collection(user_str: $user_str, user_num: $user_num + first_name: $first_name) { + user_str + user_num + last_name + first_name + } + } + VARIABLES + --- + user_str: user_str_b + first_name: non-existent + user_num: 12 + ... + + RESULT + --- + user_collection: [] + ... + + }}} + + RUN 1_3 {{{ + QUERY + query users($user_str: String, $user_num: Long, + $first_name: String) { + user_collection(user_str: $user_str, user_num: $user_num + first_name: $first_name) { + user_str + user_num + last_name + first_name + } + } + VARIABLES + --- + user_num: 12 + ... + + RESULT + --- + user_collection: + - last_name: last name a + user_str: user_str_a + first_name: first name a + user_num: 12 + - last_name: last name b + user_str: user_str_b + first_name: first name b + user_num: 12 + - last_name: last name c + user_str: user_str_c + first_name: first name c + user_num: 12 + - last_name: last name d + user_str: user_str_d + first_name: first name d + user_num: 12 + - last_name: last name e + user_str: user_str_e + first_name: first name e + user_num: 12 + ... + + }}} + + RUN 1_4 {{{ + QUERY + query users($user_str: String, $user_num: Long, + $first_name: String) { + user_collection(user_str: $user_str, user_num: $user_num + first_name: $first_name) { + user_str + user_num + last_name + first_name + } + } + VARIABLES + --- + user_str: user_str_b + ... + + RESULT + --- + user_collection: + - last_name: last name b + user_str: user_str_b + first_name: first name b + user_num: 1 + - last_name: last name b + user_str: user_str_b + first_name: first name b + user_num: 2 + - last_name: last name b + user_str: user_str_b + first_name: first name b + user_num: 3 + - last_name: last name b + user_str: user_str_b + first_name: first name b + user_num: 4 + - last_name: last name b + user_str: user_str_b + first_name: first name b + user_num: 5 + - last_name: last name b + user_str: user_str_b + first_name: first name b + user_num: 6 + - last_name: last name b + user_str: user_str_b + first_name: first name b + user_num: 7 + - last_name: last name b + user_str: user_str_b + first_name: first name b + user_num: 8 + - last_name: last name b + user_str: user_str_b + first_name: first name b + user_num: 9 + - last_name: last name b + user_str: user_str_b + first_name: first name b + user_num: 10 + - last_name: last name b + user_str: user_str_b + first_name: first name b + user_num: 11 + - last_name: last name b + user_str: user_str_b + first_name: first name b + user_num: 12 + - last_name: last name b + user_str: user_str_b + first_name: first name b + user_num: 13 + - last_name: last name b + user_str: user_str_b + first_name: first name b + user_num: 14 + - last_name: last name b + user_str: user_str_b + first_name: first name b + user_num: 15 + - last_name: last name b + user_str: user_str_b + first_name: first name b + user_num: 16 + - last_name: last name b + user_str: user_str_b + first_name: first name b + user_num: 17 + - last_name: last name b + user_str: user_str_b + first_name: first name b + user_num: 18 + - last_name: last name b + user_str: user_str_b + first_name: first name b + user_num: 19 + - last_name: last name b + user_str: user_str_b + first_name: first name b + user_num: 20 + ... + + }}} + + RUN 1_5 {{{ + QUERY + query users($user_str: String, $user_num: Long, + $first_name: String) { + user_collection(user_str: $user_str, user_num: $user_num + first_name: $first_name) { + user_str + user_num + last_name + first_name + } + } + VARIABLES + --- + first_name: non-existent + user_num: 12 + ... + + RESULT + --- + user_collection: [] + ... + + }}} + + RUN 1_6 {{{ + QUERY + query users($user_str: String, $user_num: Long, + $first_name: String) { + user_collection(user_str: $user_str, user_num: $user_num + first_name: $first_name) { + user_str + user_num + last_name + first_name + } + } + VARIABLES + --- + first_name: non-existent + user_str: user_str_b + ... + + RESULT + --- + user_collection: [] + ... + + }}} + + RUN 2_1 {{{ + QUERY + query users($user_str: String, $user_num: Long, $description: String) { + user_collection(user_str: $user_str, user_num: $user_num) { + user_str + user_num + last_name + first_name + order_connection(description: $description) { + order_str + order_num + description + } + } + } + VARIABLES + --- + user_num: 12 + user_str: user_str_b + ... + + RESULT + --- + user_collection: + - order_connection: + - order_num: 1201 + order_str: order_str_b_1 + description: description b + - order_num: 1210 + order_str: order_str_b_10 + description: description b + - order_num: 1202 + order_str: order_str_b_2 + description: description b + - order_num: 1203 + order_str: order_str_b_3 + description: description b + - order_num: 1204 + order_str: order_str_b_4 + description: description b + - order_num: 1205 + order_str: order_str_b_5 + description: description b + - order_num: 1206 + order_str: order_str_b_6 + description: description b + - order_num: 1207 + order_str: order_str_b_7 + description: description b + - order_num: 1208 + order_str: order_str_b_8 + description: description b + - order_num: 1209 + order_str: order_str_b_9 + description: description b + user_str: user_str_b + first_name: first name b + user_num: 12 + last_name: last name b + ... + + }}} + + RUN 2_2 {{{ + QUERY + query users($user_str: String, $user_num: Long, $description: String) { + user_collection(user_str: $user_str, user_num: $user_num) { + user_str + user_num + last_name + first_name + order_connection(description: $description) { + order_str + order_num + description + } + } + } + VARIABLES + --- + user_str: user_str_b + description: non-existent + user_num: 12 + ... + + RESULT + --- + user_collection: + - order_connection: [] + user_str: user_str_b + first_name: first name b + user_num: 12 + last_name: last name b + ... + + }}} + + RUN 3 {{{ + QUERY + query users($user_str: String, $user_num: Long) { + user_collection(user_str: $user_str, user_num: $user_num) { + user_str + user_num + last_name + first_name + order_str_connection { + order_str + order_num + description + } + } + } + VARIABLES + --- + user_num: 12 + user_str: user_str_b + ... + + RESULT + --- + user_collection: + - user_str: user_str_b + first_name: first name b + user_num: 12 + last_name: last name b + order_str_connection: + - order_num: 101 + order_str: order_str_b_1 + description: description b + - order_num: 110 + order_str: order_str_b_10 + description: description b + - order_num: 102 + order_str: order_str_b_2 + description: description b + - order_num: 103 + order_str: order_str_b_3 + description: description b + - order_num: 104 + order_str: order_str_b_4 + description: description b + - order_num: 105 + order_str: order_str_b_5 + description: description b + - order_num: 106 + order_str: order_str_b_6 + description: description b + - order_num: 107 + order_str: order_str_b_7 + description: description b + - order_num: 108 + order_str: order_str_b_8 + description: description b + - order_num: 201 + order_str: order_str_b_1 + description: description b + - order_num: 210 + order_str: order_str_b_10 + description: description b + - order_num: 202 + order_str: order_str_b_2 + description: description b + - order_num: 205 + order_str: order_str_b_5 + description: description b + - order_num: 208 + order_str: order_str_b_8 + description: description b + - order_num: 301 + order_str: order_str_b_1 + description: description b + - order_num: 310 + order_str: order_str_b_10 + description: description b + - order_num: 302 + order_str: order_str_b_2 + description: description b + - order_num: 305 + order_str: order_str_b_5 + description: description b + - order_num: 308 + order_str: order_str_b_8 + description: description b + - order_num: 401 + order_str: order_str_b_1 + description: description b + - order_num: 410 + order_str: order_str_b_10 + description: description b + - order_num: 402 + order_str: order_str_b_2 + description: description b + - order_num: 405 + order_str: order_str_b_5 + description: description b + - order_num: 408 + order_str: order_str_b_8 + description: description b + - order_num: 501 + order_str: order_str_b_1 + description: description b + - order_num: 510 + order_str: order_str_b_10 + description: description b + - order_num: 502 + order_str: order_str_b_2 + description: description b + - order_num: 505 + order_str: order_str_b_5 + description: description b + - order_num: 508 + order_str: order_str_b_8 + description: description b + - order_num: 601 + order_str: order_str_b_1 + description: description b + - order_num: 610 + order_str: order_str_b_10 + description: description b + - order_num: 602 + order_str: order_str_b_2 + description: description b + - order_num: 605 + order_str: order_str_b_5 + description: description b + - order_num: 608 + order_str: order_str_b_8 + description: description b + - order_num: 701 + order_str: order_str_b_1 + description: description b + - order_num: 710 + order_str: order_str_b_10 + description: description b + - order_num: 702 + order_str: order_str_b_2 + description: description b + - order_num: 705 + order_str: order_str_b_5 + description: description b + - order_num: 708 + order_str: order_str_b_8 + description: description b + - order_num: 801 + order_str: order_str_b_1 + description: description b + - order_num: 810 + order_str: order_str_b_10 + description: description b + - order_num: 802 + order_str: order_str_b_2 + description: description b + - order_num: 805 + order_str: order_str_b_5 + description: description b + - order_num: 808 + order_str: order_str_b_8 + description: description b + - order_num: 901 + order_str: order_str_b_1 + description: description b + - order_num: 910 + order_str: order_str_b_10 + description: description b + - order_num: 902 + order_str: order_str_b_2 + description: description b + - order_num: 905 + order_str: order_str_b_5 + description: description b + - order_num: 908 + order_str: order_str_b_8 + description: description b + - order_num: 1001 + order_str: order_str_b_1 + description: description b + - order_num: 1010 + order_str: order_str_b_10 + description: description b + - order_num: 1002 + order_str: order_str_b_2 + description: description b + - order_num: 1005 + order_str: order_str_b_5 + description: description b + - order_num: 1008 + order_str: order_str_b_8 + description: description b + - order_num: 1101 + order_str: order_str_b_1 + description: description b + - order_num: 1110 + order_str: order_str_b_10 + description: description b + - order_num: 1102 + order_str: order_str_b_2 + description: description b + - order_num: 1105 + order_str: order_str_b_5 + description: description b + - order_num: 1108 + order_str: order_str_b_8 + description: description b + - order_num: 1201 + order_str: order_str_b_1 + description: description b + - order_num: 1210 + order_str: order_str_b_10 + description: description b + - order_num: 1202 + order_str: order_str_b_2 + description: description b + - order_num: 1205 + order_str: order_str_b_5 + description: description b + - order_num: 1208 + order_str: order_str_b_8 + description: description b + - order_num: 1301 + order_str: order_str_b_1 + description: description b + - order_num: 1310 + order_str: order_str_b_10 + description: description b + - order_num: 1302 + order_str: order_str_b_2 + description: description b + - order_num: 1305 + order_str: order_str_b_5 + description: description b + - order_num: 1308 + order_str: order_str_b_8 + description: description b + - order_num: 1401 + order_str: order_str_b_1 + description: description b + - order_num: 1410 + order_str: order_str_b_10 + description: description b + - order_num: 1402 + order_str: order_str_b_2 + description: description b + - order_num: 1405 + order_str: order_str_b_5 + description: description b + - order_num: 1408 + order_str: order_str_b_8 + description: description b + - order_num: 1501 + order_str: order_str_b_1 + description: description b + - order_num: 1510 + order_str: order_str_b_10 + description: description b + - order_num: 1502 + order_str: order_str_b_2 + description: description b + - order_num: 1505 + order_str: order_str_b_5 + description: description b + - order_num: 1508 + order_str: order_str_b_8 + description: description b + - order_num: 1601 + order_str: order_str_b_1 + description: description b + - order_num: 1610 + order_str: order_str_b_10 + description: description b + - order_num: 1602 + order_str: order_str_b_2 + description: description b + - order_num: 1605 + order_str: order_str_b_5 + description: description b + - order_num: 1608 + order_str: order_str_b_8 + description: description b + - order_num: 1701 + order_str: order_str_b_1 + description: description b + - order_num: 1710 + order_str: order_str_b_10 + description: description b + - order_num: 1702 + order_str: order_str_b_2 + description: description b + - order_num: 1705 + order_str: order_str_b_5 + description: description b + - order_num: 1708 + order_str: order_str_b_8 + description: description b + - order_num: 1801 + order_str: order_str_b_1 + description: description b + - order_num: 1810 + order_str: order_str_b_10 + description: description b + - order_num: 1802 + order_str: order_str_b_2 + description: description b + - order_num: 1805 + order_str: order_str_b_5 + description: description b + - order_num: 1808 + order_str: order_str_b_8 + description: description b + - order_num: 1901 + order_str: order_str_b_1 + description: description b + - order_num: 1910 + order_str: order_str_b_10 + description: description b + - order_num: 1902 + order_str: order_str_b_2 + description: description b + - order_num: 1905 + order_str: order_str_b_5 + description: description b + - order_num: 1908 + order_str: order_str_b_8 + description: description b + - order_num: 2001 + order_str: order_str_b_1 + description: description b + - order_num: 2010 + order_str: order_str_b_10 + description: description b + - order_num: 2002 + order_str: order_str_b_2 + description: description b + - order_num: 2005 + order_str: order_str_b_5 + description: description b + - order_num: 2008 + order_str: order_str_b_8 + description: description b + - order_num: 109 + order_str: order_str_b_9 + description: description b + - order_num: 203 + order_str: order_str_b_3 + description: description b + - order_num: 204 + order_str: order_str_b_4 + description: description b + - order_num: 206 + order_str: order_str_b_6 + description: description b + - order_num: 207 + order_str: order_str_b_7 + description: description b + - order_num: 209 + order_str: order_str_b_9 + description: description b + - order_num: 303 + order_str: order_str_b_3 + description: description b + - order_num: 304 + order_str: order_str_b_4 + description: description b + - order_num: 306 + order_str: order_str_b_6 + description: description b + - order_num: 307 + order_str: order_str_b_7 + description: description b + - order_num: 309 + order_str: order_str_b_9 + description: description b + - order_num: 403 + order_str: order_str_b_3 + description: description b + - order_num: 404 + order_str: order_str_b_4 + description: description b + - order_num: 406 + order_str: order_str_b_6 + description: description b + - order_num: 407 + order_str: order_str_b_7 + description: description b + - order_num: 409 + order_str: order_str_b_9 + description: description b + - order_num: 503 + order_str: order_str_b_3 + description: description b + - order_num: 504 + order_str: order_str_b_4 + description: description b + - order_num: 506 + order_str: order_str_b_6 + description: description b + - order_num: 507 + order_str: order_str_b_7 + description: description b + - order_num: 509 + order_str: order_str_b_9 + description: description b + - order_num: 603 + order_str: order_str_b_3 + description: description b + - order_num: 604 + order_str: order_str_b_4 + description: description b + - order_num: 606 + order_str: order_str_b_6 + description: description b + - order_num: 607 + order_str: order_str_b_7 + description: description b + - order_num: 609 + order_str: order_str_b_9 + description: description b + - order_num: 703 + order_str: order_str_b_3 + description: description b + - order_num: 704 + order_str: order_str_b_4 + description: description b + - order_num: 706 + order_str: order_str_b_6 + description: description b + - order_num: 707 + order_str: order_str_b_7 + description: description b + - order_num: 709 + order_str: order_str_b_9 + description: description b + - order_num: 803 + order_str: order_str_b_3 + description: description b + - order_num: 804 + order_str: order_str_b_4 + description: description b + - order_num: 806 + order_str: order_str_b_6 + description: description b + - order_num: 807 + order_str: order_str_b_7 + description: description b + - order_num: 809 + order_str: order_str_b_9 + description: description b + - order_num: 903 + order_str: order_str_b_3 + description: description b + - order_num: 904 + order_str: order_str_b_4 + description: description b + - order_num: 906 + order_str: order_str_b_6 + description: description b + - order_num: 907 + order_str: order_str_b_7 + description: description b + - order_num: 909 + order_str: order_str_b_9 + description: description b + - order_num: 1003 + order_str: order_str_b_3 + description: description b + - order_num: 1004 + order_str: order_str_b_4 + description: description b + - order_num: 1006 + order_str: order_str_b_6 + description: description b + - order_num: 1007 + order_str: order_str_b_7 + description: description b + - order_num: 1009 + order_str: order_str_b_9 + description: description b + - order_num: 1103 + order_str: order_str_b_3 + description: description b + - order_num: 1104 + order_str: order_str_b_4 + description: description b + - order_num: 1106 + order_str: order_str_b_6 + description: description b + - order_num: 1107 + order_str: order_str_b_7 + description: description b + - order_num: 1109 + order_str: order_str_b_9 + description: description b + - order_num: 1203 + order_str: order_str_b_3 + description: description b + - order_num: 1204 + order_str: order_str_b_4 + description: description b + - order_num: 1206 + order_str: order_str_b_6 + description: description b + - order_num: 1207 + order_str: order_str_b_7 + description: description b + - order_num: 1209 + order_str: order_str_b_9 + description: description b + - order_num: 1303 + order_str: order_str_b_3 + description: description b + - order_num: 1304 + order_str: order_str_b_4 + description: description b + - order_num: 1306 + order_str: order_str_b_6 + description: description b + - order_num: 1307 + order_str: order_str_b_7 + description: description b + - order_num: 1309 + order_str: order_str_b_9 + description: description b + - order_num: 1403 + order_str: order_str_b_3 + description: description b + - order_num: 1404 + order_str: order_str_b_4 + description: description b + - order_num: 1406 + order_str: order_str_b_6 + description: description b + - order_num: 1407 + order_str: order_str_b_7 + description: description b + - order_num: 1409 + order_str: order_str_b_9 + description: description b + - order_num: 1503 + order_str: order_str_b_3 + description: description b + - order_num: 1504 + order_str: order_str_b_4 + description: description b + - order_num: 1506 + order_str: order_str_b_6 + description: description b + - order_num: 1507 + order_str: order_str_b_7 + description: description b + - order_num: 1509 + order_str: order_str_b_9 + description: description b + - order_num: 1603 + order_str: order_str_b_3 + description: description b + - order_num: 1604 + order_str: order_str_b_4 + description: description b + - order_num: 1606 + order_str: order_str_b_6 + description: description b + - order_num: 1607 + order_str: order_str_b_7 + description: description b + - order_num: 1609 + order_str: order_str_b_9 + description: description b + - order_num: 1703 + order_str: order_str_b_3 + description: description b + - order_num: 1704 + order_str: order_str_b_4 + description: description b + - order_num: 1706 + order_str: order_str_b_6 + description: description b + - order_num: 1707 + order_str: order_str_b_7 + description: description b + - order_num: 1709 + order_str: order_str_b_9 + description: description b + - order_num: 1803 + order_str: order_str_b_3 + description: description b + - order_num: 1804 + order_str: order_str_b_4 + description: description b + - order_num: 1806 + order_str: order_str_b_6 + description: description b + - order_num: 1807 + order_str: order_str_b_7 + description: description b + - order_num: 1809 + order_str: order_str_b_9 + description: description b + - order_num: 1903 + order_str: order_str_b_3 + description: description b + - order_num: 1904 + order_str: order_str_b_4 + description: description b + - order_num: 1906 + order_str: order_str_b_6 + description: description b + - order_num: 1907 + order_str: order_str_b_7 + description: description b + - order_num: 1909 + order_str: order_str_b_9 + description: description b + - order_num: 2003 + order_str: order_str_b_3 + description: description b + - order_num: 2004 + order_str: order_str_b_4 + description: description b + - order_num: 2006 + order_str: order_str_b_6 + description: description b + - order_num: 2007 + order_str: order_str_b_7 + description: description b + - order_num: 2009 + order_str: order_str_b_9 + description: description b + ... + + }}} + + RUN 4_1 {{{ + QUERY + query users($limit: Int, $offset: user_collection_offset) { + user_collection(limit: $limit, offset: $offset) { + user_str + user_num + last_name + first_name + } + } + VARIABLES + --- + offset: + user_num: 12 + user_str: user_str_b + limit: 10 + ... + + RESULT + --- + user_collection: + - last_name: last name b + user_str: user_str_b + first_name: first name b + user_num: 13 + - last_name: last name b + user_str: user_str_b + first_name: first name b + user_num: 14 + - last_name: last name b + user_str: user_str_b + first_name: first name b + user_num: 15 + - last_name: last name b + user_str: user_str_b + first_name: first name b + user_num: 16 + - last_name: last name b + user_str: user_str_b + first_name: first name b + user_num: 17 + - last_name: last name b + user_str: user_str_b + first_name: first name b + user_num: 18 + - last_name: last name b + user_str: user_str_b + first_name: first name b + user_num: 19 + - last_name: last name b + user_str: user_str_b + first_name: first name b + user_num: 20 + - last_name: last name c + user_str: user_str_c + first_name: first name c + user_num: 1 + - last_name: last name c + user_str: user_str_c + first_name: first name c + user_num: 2 + ... + + }}} + + RUN 4_2 {{{ + QUERY + query users($limit: Int, $offset: user_collection_offset) { + user_collection(limit: $limit, offset: $offset) { + user_str + user_num + last_name + first_name + } + } + VARIABLES + --- + offset: + user_str: user_str_b + limit: 10 + ... + + RESULT + --- + ok: false + err: offset by a partial key is forbidden + ... + + }}} + + RUN 5_1 {{{ + QUERY + query users($user_str: String, $user_num: Long, + $limit: Int, $offset: order_collection_offset) { + user_collection(user_str: $user_str, user_num: $user_num) { + user_str + user_num + last_name + first_name + order_connection(limit: $limit, offset: $offset) { + order_str + order_num + description + } + } + } + VARIABLES + --- + offset: + order_num: 1202 + order_str: order_str_b_2 + user_str: user_str_b + limit: 4 + user_num: 12 + ... + + RESULT + --- + user_collection: + - order_connection: + - order_num: 1203 + order_str: order_str_b_3 + description: description b + - order_num: 1204 + order_str: order_str_b_4 + description: description b + - order_num: 1205 + order_str: order_str_b_5 + description: description b + - order_num: 1206 + order_str: order_str_b_6 + description: description b + user_str: user_str_b + first_name: first name b + user_num: 12 + last_name: last name b + ... + + }}} + + RUN 5_2 {{{ + QUERY + query users($user_str: String, $user_num: Long, + $limit: Int, $offset: order_collection_offset) { + user_collection(user_str: $user_str, user_num: $user_num) { + user_str + user_num + last_name + first_name + order_connection(limit: $limit, offset: $offset) { + order_str + order_num + description + } + } + } + VARIABLES + --- + offset: + order_str: order_str_b_2 + user_str: user_str_b + limit: 4 + user_num: 12 + ... + + RESULT + --- + ok: false + err: 'offset by a partial key is forbidden: expected "order_num" field' + ... + + }}} + +... +-- clean up +-- -------- +test_run:cmd('switch shard1') +--- +- true +... +require('test.testdata.compound_index_testdata').drop_spaces() +--- +... +test_run:cmd('switch shard2') +--- +- true +... +require('test.testdata.compound_index_testdata').drop_spaces() +--- +... +test_run:cmd('switch default') +--- +- true +... +test_run:drop_cluster(SERVERS) +--- +... diff --git a/test/shard_no_redundancy/shard_compound_index.test.lua b/test/shard_no_redundancy/shard_compound_index.test.lua new file mode 100644 index 0000000..1be9988 --- /dev/null +++ b/test/shard_no_redundancy/shard_compound_index.test.lua @@ -0,0 +1,77 @@ +env = require('test_run') +test_run = env.new() + +shard = require('shard') + +test_run:cmd("setopt delimiter ';'") +SERVERS = {'shard1', 'shard2'}; +init_shard(SERVERS, { + servers = { + { uri = instance_uri('1'), zone = '0' }, + { uri = instance_uri('2'), zone = '1' }, + }, + login = 'guest', + password = '', + redundancy = 1, +}, 'shard_no_redundancy'); +test_run:cmd("setopt delimiter ''"); + +fio = require('fio') + +-- require in-repo version of graphql/ sources despite current working directory +package.path = fio.abspath(debug.getinfo(1).source:match("@?(.*/)"):gsub('/./', '/'):gsub('/+$', '')) .. '/../../?.lua' .. ';' .. package.path + +graphql = require('graphql') +testdata = require('test.testdata.compound_index_testdata') + +-- init box, upload test data and acquire metadata +-- ----------------------------------------------- + +-- init box and data schema +test_run:cmd('switch shard1') +require('test.testdata.compound_index_testdata').init_spaces() +test_run:cmd('switch shard2') +require('test.testdata.compound_index_testdata').init_spaces() +test_run:cmd('switch default') +shard.reload_schema() + +-- upload test data +testdata.fill_test_data(shard) + +-- acquire metadata +metadata = testdata.get_test_metadata() +schemas = metadata.schemas +collections = metadata.collections +service_fields = metadata.service_fields +indexes = metadata.indexes + +-- build accessor and graphql schemas +-- ---------------------------------- + +test_run:cmd("setopt delimiter ';'") +accessor = graphql.accessor_shard.new({ + schemas = schemas, + collections = collections, + service_fields = service_fields, + indexes = indexes, +}); + +gql_wrapper = graphql.new({ + schemas = schemas, + collections = collections, + accessor = accessor, +}); +test_run:cmd("setopt delimiter ''"); + +testdata.run_queries(gql_wrapper) + +-- clean up +-- -------- + +test_run:cmd('switch shard1') +require('test.testdata.compound_index_testdata').drop_spaces() +test_run:cmd('switch shard2') +require('test.testdata.compound_index_testdata').drop_spaces() +test_run:cmd('switch default') + +test_run:drop_cluster(SERVERS) diff --git a/test/shard_redundancy/no_duplicates.result b/test/shard_redundancy/no_duplicates.result index ab92449..a161f1a 100644 --- a/test/shard_redundancy/no_duplicates.result +++ b/test/shard_redundancy/no_duplicates.result @@ -81,6 +81,9 @@ test_run:cmd('switch default') --- - true ... +shard.reload_schema() +--- +... -- upload test data testdata.fill_test_data(shard) --- diff --git a/test/shard_redundancy/no_duplicates.test.lua b/test/shard_redundancy/no_duplicates.test.lua index 4b6a1a1..caa631a 100644 --- a/test/shard_redundancy/no_duplicates.test.lua +++ b/test/shard_redundancy/no_duplicates.test.lua @@ -42,6 +42,7 @@ require('test.testdata.common_testdata').init_spaces() test_run:cmd('switch shard4') require('test.testdata.common_testdata').init_spaces() test_run:cmd('switch default') +shard.reload_schema() -- upload test data testdata.fill_test_data(shard) diff --git a/test/shard_redundancy/nullable_index.result b/test/shard_redundancy/nullable_index.result index 3ba91ed..40f35d2 100644 --- a/test/shard_redundancy/nullable_index.result +++ b/test/shard_redundancy/nullable_index.result @@ -84,6 +84,9 @@ test_run:cmd('switch default') --- - true ... +shard.reload_schema() +--- +... -- upload test data testdata.fill_test_data(shard) --- diff --git a/test/shard_redundancy/nullable_index.test.lua b/test/shard_redundancy/nullable_index.test.lua index 14a71ed..195aece 100644 --- a/test/shard_redundancy/nullable_index.test.lua +++ b/test/shard_redundancy/nullable_index.test.lua @@ -46,6 +46,7 @@ require('test.testdata.nullable_index_testdata').init_spaces() test_run:cmd('switch shard4') require('test.testdata.nullable_index_testdata').init_spaces() test_run:cmd('switch default') +shard.reload_schema() -- upload test data testdata.fill_test_data(shard) diff --git a/test/shard_redundancy/shard_compound_index.result b/test/shard_redundancy/shard_compound_index.result new file mode 100644 index 0000000..92a11ae --- /dev/null +++ b/test/shard_redundancy/shard_compound_index.result @@ -0,0 +1,1328 @@ +env = require('test_run') +--- +... +test_run = env.new() +--- +... +shard = require('shard') +--- +... +-- we need at least four servers to make sure we have several (two) servers +-- within each replica set and several (two) replica sets +test_run:cmd("setopt delimiter ';'") +--- +- true +... +SERVERS = {'shard1', 'shard2', 'shard3', 'shard4'}; +--- +... +init_shard(SERVERS, { + servers = { + { uri = instance_uri('1'), zone = '0' }, + { uri = instance_uri('2'), zone = '1' }, + { uri = instance_uri('3'), zone = '2' }, + { uri = instance_uri('4'), zone = '3' }, + }, + login = 'guest', + password = '', + redundancy = 2, +}, 'shard_redundancy'); +--- +... +test_run:cmd("setopt delimiter ''"); +--- +- true +... +fio = require('fio') +--- +... +-- require in-repo version of graphql/ sources despite current working directory +package.path = fio.abspath(debug.getinfo(1).source:match("@?(.*/)"):gsub('/./', '/'):gsub('/+$', '')) .. '/../../?.lua' .. ';' .. package.path +--- +... +graphql = require('graphql') +--- +... +testdata = require('test.testdata.compound_index_testdata') +--- +... +-- init box, upload test data and acquire metadata +-- ----------------------------------------------- +-- init box and data schema +test_run:cmd('switch shard1') +--- +- true +... +require('test.testdata.compound_index_testdata').init_spaces() +--- +... +test_run:cmd('switch shard2') +--- +- true +... +require('test.testdata.compound_index_testdata').init_spaces() +--- +... +test_run:cmd('switch shard3') +--- +- true +... +require('test.testdata.compound_index_testdata').init_spaces() +--- +... +test_run:cmd('switch shard4') +--- +- true +... +require('test.testdata.compound_index_testdata').init_spaces() +--- +... +test_run:cmd('switch default') +--- +- true +... +-- upload test data +testdata.fill_test_data(shard) +--- +... +shard.reload_schema() +--- +... +-- acquire metadata +metadata = testdata.get_test_metadata() +--- +... +schemas = metadata.schemas +--- +... +collections = metadata.collections +--- +... +service_fields = metadata.service_fields +--- +... +indexes = metadata.indexes +--- +... +-- build accessor and graphql schemas +-- ---------------------------------- +test_run:cmd("setopt delimiter ';'") +--- +- true +... +accessor = graphql.accessor_shard.new({ + schemas = schemas, + collections = collections, + service_fields = service_fields, + indexes = indexes, +}); +--- +... +gql_wrapper = graphql.new({ + schemas = schemas, + collections = collections, + accessor = accessor, +}); +--- +... +test_run:cmd("setopt delimiter ''"); +--- +- true +... +testdata.run_queries(gql_wrapper) +--- +- |+ + RUN 1_1 {{{ + QUERY + query users($user_str: String, $user_num: Long, + $first_name: String) { + user_collection(user_str: $user_str, user_num: $user_num + first_name: $first_name) { + user_str + user_num + last_name + first_name + } + } + VARIABLES + --- + user_num: 12 + user_str: user_str_b + ... + + RESULT + --- + user_collection: + - last_name: last name b + user_str: user_str_b + first_name: first name b + user_num: 12 + ... + + }}} + + RUN 1_2 {{{ + QUERY + query users($user_str: String, $user_num: Long, + $first_name: String) { + user_collection(user_str: $user_str, user_num: $user_num + first_name: $first_name) { + user_str + user_num + last_name + first_name + } + } + VARIABLES + --- + user_str: user_str_b + first_name: non-existent + user_num: 12 + ... + + RESULT + --- + user_collection: [] + ... + + }}} + + RUN 1_3 {{{ + QUERY + query users($user_str: String, $user_num: Long, + $first_name: String) { + user_collection(user_str: $user_str, user_num: $user_num + first_name: $first_name) { + user_str + user_num + last_name + first_name + } + } + VARIABLES + --- + user_num: 12 + ... + + RESULT + --- + user_collection: + - last_name: last name a + user_str: user_str_a + first_name: first name a + user_num: 12 + - last_name: last name b + user_str: user_str_b + first_name: first name b + user_num: 12 + - last_name: last name c + user_str: user_str_c + first_name: first name c + user_num: 12 + - last_name: last name d + user_str: user_str_d + first_name: first name d + user_num: 12 + - last_name: last name e + user_str: user_str_e + first_name: first name e + user_num: 12 + ... + + }}} + + RUN 1_4 {{{ + QUERY + query users($user_str: String, $user_num: Long, + $first_name: String) { + user_collection(user_str: $user_str, user_num: $user_num + first_name: $first_name) { + user_str + user_num + last_name + first_name + } + } + VARIABLES + --- + user_str: user_str_b + ... + + RESULT + --- + user_collection: + - last_name: last name b + user_str: user_str_b + first_name: first name b + user_num: 1 + - last_name: last name b + user_str: user_str_b + first_name: first name b + user_num: 2 + - last_name: last name b + user_str: user_str_b + first_name: first name b + user_num: 3 + - last_name: last name b + user_str: user_str_b + first_name: first name b + user_num: 4 + - last_name: last name b + user_str: user_str_b + first_name: first name b + user_num: 5 + - last_name: last name b + user_str: user_str_b + first_name: first name b + user_num: 6 + - last_name: last name b + user_str: user_str_b + first_name: first name b + user_num: 7 + - last_name: last name b + user_str: user_str_b + first_name: first name b + user_num: 8 + - last_name: last name b + user_str: user_str_b + first_name: first name b + user_num: 9 + - last_name: last name b + user_str: user_str_b + first_name: first name b + user_num: 10 + - last_name: last name b + user_str: user_str_b + first_name: first name b + user_num: 11 + - last_name: last name b + user_str: user_str_b + first_name: first name b + user_num: 12 + - last_name: last name b + user_str: user_str_b + first_name: first name b + user_num: 13 + - last_name: last name b + user_str: user_str_b + first_name: first name b + user_num: 14 + - last_name: last name b + user_str: user_str_b + first_name: first name b + user_num: 15 + - last_name: last name b + user_str: user_str_b + first_name: first name b + user_num: 16 + - last_name: last name b + user_str: user_str_b + first_name: first name b + user_num: 17 + - last_name: last name b + user_str: user_str_b + first_name: first name b + user_num: 18 + - last_name: last name b + user_str: user_str_b + first_name: first name b + user_num: 19 + - last_name: last name b + user_str: user_str_b + first_name: first name b + user_num: 20 + ... + + }}} + + RUN 1_5 {{{ + QUERY + query users($user_str: String, $user_num: Long, + $first_name: String) { + user_collection(user_str: $user_str, user_num: $user_num + first_name: $first_name) { + user_str + user_num + last_name + first_name + } + } + VARIABLES + --- + first_name: non-existent + user_num: 12 + ... + + RESULT + --- + user_collection: [] + ... + + }}} + + RUN 1_6 {{{ + QUERY + query users($user_str: String, $user_num: Long, + $first_name: String) { + user_collection(user_str: $user_str, user_num: $user_num + first_name: $first_name) { + user_str + user_num + last_name + first_name + } + } + VARIABLES + --- + first_name: non-existent + user_str: user_str_b + ... + + RESULT + --- + user_collection: [] + ... + + }}} + + RUN 2_1 {{{ + QUERY + query users($user_str: String, $user_num: Long, $description: String) { + user_collection(user_str: $user_str, user_num: $user_num) { + user_str + user_num + last_name + first_name + order_connection(description: $description) { + order_str + order_num + description + } + } + } + VARIABLES + --- + user_num: 12 + user_str: user_str_b + ... + + RESULT + --- + user_collection: + - order_connection: + - order_num: 1201 + order_str: order_str_b_1 + description: description b + - order_num: 1210 + order_str: order_str_b_10 + description: description b + - order_num: 1202 + order_str: order_str_b_2 + description: description b + - order_num: 1203 + order_str: order_str_b_3 + description: description b + - order_num: 1204 + order_str: order_str_b_4 + description: description b + - order_num: 1205 + order_str: order_str_b_5 + description: description b + - order_num: 1206 + order_str: order_str_b_6 + description: description b + - order_num: 1207 + order_str: order_str_b_7 + description: description b + - order_num: 1208 + order_str: order_str_b_8 + description: description b + - order_num: 1209 + order_str: order_str_b_9 + description: description b + user_str: user_str_b + first_name: first name b + user_num: 12 + last_name: last name b + ... + + }}} + + RUN 2_2 {{{ + QUERY + query users($user_str: String, $user_num: Long, $description: String) { + user_collection(user_str: $user_str, user_num: $user_num) { + user_str + user_num + last_name + first_name + order_connection(description: $description) { + order_str + order_num + description + } + } + } + VARIABLES + --- + user_str: user_str_b + description: non-existent + user_num: 12 + ... + + RESULT + --- + user_collection: + - order_connection: [] + user_str: user_str_b + first_name: first name b + user_num: 12 + last_name: last name b + ... + + }}} + + RUN 3 {{{ + QUERY + query users($user_str: String, $user_num: Long) { + user_collection(user_str: $user_str, user_num: $user_num) { + user_str + user_num + last_name + first_name + order_str_connection { + order_str + order_num + description + } + } + } + VARIABLES + --- + user_num: 12 + user_str: user_str_b + ... + + RESULT + --- + user_collection: + - user_str: user_str_b + first_name: first name b + user_num: 12 + last_name: last name b + order_str_connection: + - order_num: 101 + order_str: order_str_b_1 + description: description b + - order_num: 110 + order_str: order_str_b_10 + description: description b + - order_num: 102 + order_str: order_str_b_2 + description: description b + - order_num: 103 + order_str: order_str_b_3 + description: description b + - order_num: 104 + order_str: order_str_b_4 + description: description b + - order_num: 105 + order_str: order_str_b_5 + description: description b + - order_num: 106 + order_str: order_str_b_6 + description: description b + - order_num: 107 + order_str: order_str_b_7 + description: description b + - order_num: 108 + order_str: order_str_b_8 + description: description b + - order_num: 201 + order_str: order_str_b_1 + description: description b + - order_num: 210 + order_str: order_str_b_10 + description: description b + - order_num: 202 + order_str: order_str_b_2 + description: description b + - order_num: 205 + order_str: order_str_b_5 + description: description b + - order_num: 208 + order_str: order_str_b_8 + description: description b + - order_num: 301 + order_str: order_str_b_1 + description: description b + - order_num: 310 + order_str: order_str_b_10 + description: description b + - order_num: 302 + order_str: order_str_b_2 + description: description b + - order_num: 305 + order_str: order_str_b_5 + description: description b + - order_num: 308 + order_str: order_str_b_8 + description: description b + - order_num: 401 + order_str: order_str_b_1 + description: description b + - order_num: 410 + order_str: order_str_b_10 + description: description b + - order_num: 402 + order_str: order_str_b_2 + description: description b + - order_num: 405 + order_str: order_str_b_5 + description: description b + - order_num: 408 + order_str: order_str_b_8 + description: description b + - order_num: 501 + order_str: order_str_b_1 + description: description b + - order_num: 510 + order_str: order_str_b_10 + description: description b + - order_num: 502 + order_str: order_str_b_2 + description: description b + - order_num: 505 + order_str: order_str_b_5 + description: description b + - order_num: 508 + order_str: order_str_b_8 + description: description b + - order_num: 601 + order_str: order_str_b_1 + description: description b + - order_num: 610 + order_str: order_str_b_10 + description: description b + - order_num: 602 + order_str: order_str_b_2 + description: description b + - order_num: 605 + order_str: order_str_b_5 + description: description b + - order_num: 608 + order_str: order_str_b_8 + description: description b + - order_num: 701 + order_str: order_str_b_1 + description: description b + - order_num: 710 + order_str: order_str_b_10 + description: description b + - order_num: 702 + order_str: order_str_b_2 + description: description b + - order_num: 705 + order_str: order_str_b_5 + description: description b + - order_num: 708 + order_str: order_str_b_8 + description: description b + - order_num: 801 + order_str: order_str_b_1 + description: description b + - order_num: 810 + order_str: order_str_b_10 + description: description b + - order_num: 802 + order_str: order_str_b_2 + description: description b + - order_num: 805 + order_str: order_str_b_5 + description: description b + - order_num: 808 + order_str: order_str_b_8 + description: description b + - order_num: 901 + order_str: order_str_b_1 + description: description b + - order_num: 910 + order_str: order_str_b_10 + description: description b + - order_num: 902 + order_str: order_str_b_2 + description: description b + - order_num: 905 + order_str: order_str_b_5 + description: description b + - order_num: 908 + order_str: order_str_b_8 + description: description b + - order_num: 1001 + order_str: order_str_b_1 + description: description b + - order_num: 1010 + order_str: order_str_b_10 + description: description b + - order_num: 1002 + order_str: order_str_b_2 + description: description b + - order_num: 1005 + order_str: order_str_b_5 + description: description b + - order_num: 1008 + order_str: order_str_b_8 + description: description b + - order_num: 1101 + order_str: order_str_b_1 + description: description b + - order_num: 1110 + order_str: order_str_b_10 + description: description b + - order_num: 1102 + order_str: order_str_b_2 + description: description b + - order_num: 1105 + order_str: order_str_b_5 + description: description b + - order_num: 1108 + order_str: order_str_b_8 + description: description b + - order_num: 1201 + order_str: order_str_b_1 + description: description b + - order_num: 1210 + order_str: order_str_b_10 + description: description b + - order_num: 1202 + order_str: order_str_b_2 + description: description b + - order_num: 1205 + order_str: order_str_b_5 + description: description b + - order_num: 1208 + order_str: order_str_b_8 + description: description b + - order_num: 1301 + order_str: order_str_b_1 + description: description b + - order_num: 1310 + order_str: order_str_b_10 + description: description b + - order_num: 1302 + order_str: order_str_b_2 + description: description b + - order_num: 1305 + order_str: order_str_b_5 + description: description b + - order_num: 1308 + order_str: order_str_b_8 + description: description b + - order_num: 1401 + order_str: order_str_b_1 + description: description b + - order_num: 1410 + order_str: order_str_b_10 + description: description b + - order_num: 1402 + order_str: order_str_b_2 + description: description b + - order_num: 1405 + order_str: order_str_b_5 + description: description b + - order_num: 1408 + order_str: order_str_b_8 + description: description b + - order_num: 1501 + order_str: order_str_b_1 + description: description b + - order_num: 1510 + order_str: order_str_b_10 + description: description b + - order_num: 1502 + order_str: order_str_b_2 + description: description b + - order_num: 1505 + order_str: order_str_b_5 + description: description b + - order_num: 1508 + order_str: order_str_b_8 + description: description b + - order_num: 1601 + order_str: order_str_b_1 + description: description b + - order_num: 1610 + order_str: order_str_b_10 + description: description b + - order_num: 1602 + order_str: order_str_b_2 + description: description b + - order_num: 1605 + order_str: order_str_b_5 + description: description b + - order_num: 1608 + order_str: order_str_b_8 + description: description b + - order_num: 1701 + order_str: order_str_b_1 + description: description b + - order_num: 1710 + order_str: order_str_b_10 + description: description b + - order_num: 1702 + order_str: order_str_b_2 + description: description b + - order_num: 1705 + order_str: order_str_b_5 + description: description b + - order_num: 1708 + order_str: order_str_b_8 + description: description b + - order_num: 1801 + order_str: order_str_b_1 + description: description b + - order_num: 1810 + order_str: order_str_b_10 + description: description b + - order_num: 1802 + order_str: order_str_b_2 + description: description b + - order_num: 1805 + order_str: order_str_b_5 + description: description b + - order_num: 1808 + order_str: order_str_b_8 + description: description b + - order_num: 1901 + order_str: order_str_b_1 + description: description b + - order_num: 1910 + order_str: order_str_b_10 + description: description b + - order_num: 1902 + order_str: order_str_b_2 + description: description b + - order_num: 1905 + order_str: order_str_b_5 + description: description b + - order_num: 1908 + order_str: order_str_b_8 + description: description b + - order_num: 2001 + order_str: order_str_b_1 + description: description b + - order_num: 2010 + order_str: order_str_b_10 + description: description b + - order_num: 2002 + order_str: order_str_b_2 + description: description b + - order_num: 2005 + order_str: order_str_b_5 + description: description b + - order_num: 2008 + order_str: order_str_b_8 + description: description b + - order_num: 109 + order_str: order_str_b_9 + description: description b + - order_num: 203 + order_str: order_str_b_3 + description: description b + - order_num: 204 + order_str: order_str_b_4 + description: description b + - order_num: 206 + order_str: order_str_b_6 + description: description b + - order_num: 207 + order_str: order_str_b_7 + description: description b + - order_num: 209 + order_str: order_str_b_9 + description: description b + - order_num: 303 + order_str: order_str_b_3 + description: description b + - order_num: 304 + order_str: order_str_b_4 + description: description b + - order_num: 306 + order_str: order_str_b_6 + description: description b + - order_num: 307 + order_str: order_str_b_7 + description: description b + - order_num: 309 + order_str: order_str_b_9 + description: description b + - order_num: 403 + order_str: order_str_b_3 + description: description b + - order_num: 404 + order_str: order_str_b_4 + description: description b + - order_num: 406 + order_str: order_str_b_6 + description: description b + - order_num: 407 + order_str: order_str_b_7 + description: description b + - order_num: 409 + order_str: order_str_b_9 + description: description b + - order_num: 503 + order_str: order_str_b_3 + description: description b + - order_num: 504 + order_str: order_str_b_4 + description: description b + - order_num: 506 + order_str: order_str_b_6 + description: description b + - order_num: 507 + order_str: order_str_b_7 + description: description b + - order_num: 509 + order_str: order_str_b_9 + description: description b + - order_num: 603 + order_str: order_str_b_3 + description: description b + - order_num: 604 + order_str: order_str_b_4 + description: description b + - order_num: 606 + order_str: order_str_b_6 + description: description b + - order_num: 607 + order_str: order_str_b_7 + description: description b + - order_num: 609 + order_str: order_str_b_9 + description: description b + - order_num: 703 + order_str: order_str_b_3 + description: description b + - order_num: 704 + order_str: order_str_b_4 + description: description b + - order_num: 706 + order_str: order_str_b_6 + description: description b + - order_num: 707 + order_str: order_str_b_7 + description: description b + - order_num: 709 + order_str: order_str_b_9 + description: description b + - order_num: 803 + order_str: order_str_b_3 + description: description b + - order_num: 804 + order_str: order_str_b_4 + description: description b + - order_num: 806 + order_str: order_str_b_6 + description: description b + - order_num: 807 + order_str: order_str_b_7 + description: description b + - order_num: 809 + order_str: order_str_b_9 + description: description b + - order_num: 903 + order_str: order_str_b_3 + description: description b + - order_num: 904 + order_str: order_str_b_4 + description: description b + - order_num: 906 + order_str: order_str_b_6 + description: description b + - order_num: 907 + order_str: order_str_b_7 + description: description b + - order_num: 909 + order_str: order_str_b_9 + description: description b + - order_num: 1003 + order_str: order_str_b_3 + description: description b + - order_num: 1004 + order_str: order_str_b_4 + description: description b + - order_num: 1006 + order_str: order_str_b_6 + description: description b + - order_num: 1007 + order_str: order_str_b_7 + description: description b + - order_num: 1009 + order_str: order_str_b_9 + description: description b + - order_num: 1103 + order_str: order_str_b_3 + description: description b + - order_num: 1104 + order_str: order_str_b_4 + description: description b + - order_num: 1106 + order_str: order_str_b_6 + description: description b + - order_num: 1107 + order_str: order_str_b_7 + description: description b + - order_num: 1109 + order_str: order_str_b_9 + description: description b + - order_num: 1203 + order_str: order_str_b_3 + description: description b + - order_num: 1204 + order_str: order_str_b_4 + description: description b + - order_num: 1206 + order_str: order_str_b_6 + description: description b + - order_num: 1207 + order_str: order_str_b_7 + description: description b + - order_num: 1209 + order_str: order_str_b_9 + description: description b + - order_num: 1303 + order_str: order_str_b_3 + description: description b + - order_num: 1304 + order_str: order_str_b_4 + description: description b + - order_num: 1306 + order_str: order_str_b_6 + description: description b + - order_num: 1307 + order_str: order_str_b_7 + description: description b + - order_num: 1309 + order_str: order_str_b_9 + description: description b + - order_num: 1403 + order_str: order_str_b_3 + description: description b + - order_num: 1404 + order_str: order_str_b_4 + description: description b + - order_num: 1406 + order_str: order_str_b_6 + description: description b + - order_num: 1407 + order_str: order_str_b_7 + description: description b + - order_num: 1409 + order_str: order_str_b_9 + description: description b + - order_num: 1503 + order_str: order_str_b_3 + description: description b + - order_num: 1504 + order_str: order_str_b_4 + description: description b + - order_num: 1506 + order_str: order_str_b_6 + description: description b + - order_num: 1507 + order_str: order_str_b_7 + description: description b + - order_num: 1509 + order_str: order_str_b_9 + description: description b + - order_num: 1603 + order_str: order_str_b_3 + description: description b + - order_num: 1604 + order_str: order_str_b_4 + description: description b + - order_num: 1606 + order_str: order_str_b_6 + description: description b + - order_num: 1607 + order_str: order_str_b_7 + description: description b + - order_num: 1609 + order_str: order_str_b_9 + description: description b + - order_num: 1703 + order_str: order_str_b_3 + description: description b + - order_num: 1704 + order_str: order_str_b_4 + description: description b + - order_num: 1706 + order_str: order_str_b_6 + description: description b + - order_num: 1707 + order_str: order_str_b_7 + description: description b + - order_num: 1709 + order_str: order_str_b_9 + description: description b + - order_num: 1803 + order_str: order_str_b_3 + description: description b + - order_num: 1804 + order_str: order_str_b_4 + description: description b + - order_num: 1806 + order_str: order_str_b_6 + description: description b + - order_num: 1807 + order_str: order_str_b_7 + description: description b + - order_num: 1809 + order_str: order_str_b_9 + description: description b + - order_num: 1903 + order_str: order_str_b_3 + description: description b + - order_num: 1904 + order_str: order_str_b_4 + description: description b + - order_num: 1906 + order_str: order_str_b_6 + description: description b + - order_num: 1907 + order_str: order_str_b_7 + description: description b + - order_num: 1909 + order_str: order_str_b_9 + description: description b + - order_num: 2003 + order_str: order_str_b_3 + description: description b + - order_num: 2004 + order_str: order_str_b_4 + description: description b + - order_num: 2006 + order_str: order_str_b_6 + description: description b + - order_num: 2007 + order_str: order_str_b_7 + description: description b + - order_num: 2009 + order_str: order_str_b_9 + description: description b + ... + + }}} + + RUN 4_1 {{{ + QUERY + query users($limit: Int, $offset: user_collection_offset) { + user_collection(limit: $limit, offset: $offset) { + user_str + user_num + last_name + first_name + } + } + VARIABLES + --- + offset: + user_num: 12 + user_str: user_str_b + limit: 10 + ... + + RESULT + --- + user_collection: + - last_name: last name b + user_str: user_str_b + first_name: first name b + user_num: 13 + - last_name: last name b + user_str: user_str_b + first_name: first name b + user_num: 14 + - last_name: last name b + user_str: user_str_b + first_name: first name b + user_num: 15 + - last_name: last name b + user_str: user_str_b + first_name: first name b + user_num: 16 + - last_name: last name b + user_str: user_str_b + first_name: first name b + user_num: 17 + - last_name: last name b + user_str: user_str_b + first_name: first name b + user_num: 18 + - last_name: last name b + user_str: user_str_b + first_name: first name b + user_num: 19 + - last_name: last name b + user_str: user_str_b + first_name: first name b + user_num: 20 + - last_name: last name c + user_str: user_str_c + first_name: first name c + user_num: 1 + - last_name: last name c + user_str: user_str_c + first_name: first name c + user_num: 2 + ... + + }}} + + RUN 4_2 {{{ + QUERY + query users($limit: Int, $offset: user_collection_offset) { + user_collection(limit: $limit, offset: $offset) { + user_str + user_num + last_name + first_name + } + } + VARIABLES + --- + offset: + user_str: user_str_b + limit: 10 + ... + + RESULT + --- + ok: false + err: offset by a partial key is forbidden + ... + + }}} + + RUN 5_1 {{{ + QUERY + query users($user_str: String, $user_num: Long, + $limit: Int, $offset: order_collection_offset) { + user_collection(user_str: $user_str, user_num: $user_num) { + user_str + user_num + last_name + first_name + order_connection(limit: $limit, offset: $offset) { + order_str + order_num + description + } + } + } + VARIABLES + --- + offset: + order_num: 1202 + order_str: order_str_b_2 + user_str: user_str_b + limit: 4 + user_num: 12 + ... + + RESULT + --- + user_collection: + - order_connection: + - order_num: 1203 + order_str: order_str_b_3 + description: description b + - order_num: 1204 + order_str: order_str_b_4 + description: description b + - order_num: 1205 + order_str: order_str_b_5 + description: description b + - order_num: 1206 + order_str: order_str_b_6 + description: description b + user_str: user_str_b + first_name: first name b + user_num: 12 + last_name: last name b + ... + + }}} + + RUN 5_2 {{{ + QUERY + query users($user_str: String, $user_num: Long, + $limit: Int, $offset: order_collection_offset) { + user_collection(user_str: $user_str, user_num: $user_num) { + user_str + user_num + last_name + first_name + order_connection(limit: $limit, offset: $offset) { + order_str + order_num + description + } + } + } + VARIABLES + --- + offset: + order_str: order_str_b_2 + user_str: user_str_b + limit: 4 + user_num: 12 + ... + + RESULT + --- + ok: false + err: 'offset by a partial key is forbidden: expected "order_num" field' + ... + + }}} + +... +-- clean up +-- -------- +test_run:cmd('switch shard1') +--- +- true +... +require('test.testdata.compound_index_testdata').drop_spaces() +--- +... +test_run:cmd('switch shard2') +--- +- true +... +require('test.testdata.compound_index_testdata').drop_spaces() +--- +... +test_run:cmd('switch shard3') +--- +- true +... +require('test.testdata.compound_index_testdata').drop_spaces() +--- +... +test_run:cmd('switch shard4') +--- +- true +... +require('test.testdata.compound_index_testdata').drop_spaces() +--- +... +test_run:cmd('switch default') +--- +- true +... +test_run:drop_cluster(SERVERS) +--- +... diff --git a/test/shard_redundancy/shard_compound_index.test.lua b/test/shard_redundancy/shard_compound_index.test.lua new file mode 100644 index 0000000..25e179b --- /dev/null +++ b/test/shard_redundancy/shard_compound_index.test.lua @@ -0,0 +1,90 @@ +env = require('test_run') +test_run = env.new() + +shard = require('shard') + +-- we need at least four servers to make sure we have several (two) servers +-- within each replica set and several (two) replica sets + +test_run:cmd("setopt delimiter ';'") +SERVERS = {'shard1', 'shard2', 'shard3', 'shard4'}; +init_shard(SERVERS, { + servers = { + { uri = instance_uri('1'), zone = '0' }, + { uri = instance_uri('2'), zone = '1' }, + { uri = instance_uri('3'), zone = '2' }, + { uri = instance_uri('4'), zone = '3' }, + }, + login = 'guest', + password = '', + redundancy = 2, +}, 'shard_redundancy'); +test_run:cmd("setopt delimiter ''"); + +fio = require('fio') + +-- require in-repo version of graphql/ sources despite current working directory +package.path = fio.abspath(debug.getinfo(1).source:match("@?(.*/)"):gsub('/./', '/'):gsub('/+$', '')) .. '/../../?.lua' .. ';' .. package.path + +graphql = require('graphql') +testdata = require('test.testdata.compound_index_testdata') + +-- init box, upload test data and acquire metadata +-- ----------------------------------------------- + +-- init box and data schema +test_run:cmd('switch shard1') +require('test.testdata.compound_index_testdata').init_spaces() +test_run:cmd('switch shard2') +require('test.testdata.compound_index_testdata').init_spaces() +test_run:cmd('switch shard3') +require('test.testdata.compound_index_testdata').init_spaces() +test_run:cmd('switch shard4') +require('test.testdata.compound_index_testdata').init_spaces() +test_run:cmd('switch default') + +-- upload test data +testdata.fill_test_data(shard) +shard.reload_schema() + +-- acquire metadata +metadata = testdata.get_test_metadata() +schemas = metadata.schemas +collections = metadata.collections +service_fields = metadata.service_fields +indexes = metadata.indexes + +-- build accessor and graphql schemas +-- ---------------------------------- + +test_run:cmd("setopt delimiter ';'") +accessor = graphql.accessor_shard.new({ + schemas = schemas, + collections = collections, + service_fields = service_fields, + indexes = indexes, +}); + +gql_wrapper = graphql.new({ + schemas = schemas, + collections = collections, + accessor = accessor, +}); +test_run:cmd("setopt delimiter ''"); + +testdata.run_queries(gql_wrapper) + +-- clean up +-- -------- + +test_run:cmd('switch shard1') +require('test.testdata.compound_index_testdata').drop_spaces() +test_run:cmd('switch shard2') +require('test.testdata.compound_index_testdata').drop_spaces() +test_run:cmd('switch shard3') +require('test.testdata.compound_index_testdata').drop_spaces() +test_run:cmd('switch shard4') +require('test.testdata.compound_index_testdata').drop_spaces() +test_run:cmd('switch default') + +test_run:drop_cluster(SERVERS) diff --git a/test/shard_servers/master.lua b/test/shard_servers/master.lua index a6579dc..a730010 100644 --- a/test/shard_servers/master.lua +++ b/test/shard_servers/master.lua @@ -1,5 +1,7 @@ #!/usr/bin/env tarantool +local shard_initialized = false + box.cfg({ listen = os.getenv('LISTEN'), }) @@ -15,9 +17,10 @@ function init_shard(servers, config, suite) local test_run = env.new() test_run:create_cluster(servers, suite) - box.once('init_shard_module', function() + if not shard_initialized then shard.init(config) - end) + shard_initialized = true + end shard.wait_connection() end diff --git a/test/testdata/compound_index_testdata.lua b/test/testdata/compound_index_testdata.lua index e87d4d0..0117931 100644 --- a/test/testdata/compound_index_testdata.lua +++ b/test/testdata/compound_index_testdata.lua @@ -14,6 +14,11 @@ local function print_and_return(...) return table.concat({...}, ' ') .. '\n' end +local function format_result(name, query, variables, result) + return ('RUN %s {{{\nQUERY\n%s\nVARIABLES\n%s\nRESULT\n%s\n}}}\n'):format( + name, query:rstrip(), yaml.encode(variables), yaml.encode(result)) +end + -- schemas and meta-information -- ---------------------------- @@ -201,8 +206,10 @@ function compound_index_testdata.run_queries(gql_wrapper) -- ----------------------------------------------------- local query_1 = [[ - query users($user_str: String, $user_num: Long) { - user_collection(user_str: $user_str, user_num: $user_num) { + query users($user_str: String, $user_num: Long, + $first_name: String) { + user_collection(user_str: $user_str, user_num: $user_num + first_name: $first_name) { user_str user_num last_name @@ -216,8 +223,22 @@ function compound_index_testdata.run_queries(gql_wrapper) utils.show_trace(function() local variables_1_1 = {user_str = 'user_str_b', user_num = 12} local result = gql_query_1:execute(variables_1_1) - results = results .. print_and_return( - ('RESULT\n%s'):format(yaml.encode(result))) + results = results .. print_and_return(format_result( + '1_1', query_1, variables_1_1, result)) + end) + + -- get a top-level object by a full compound primary key plus filter + -- ----------------------------------------------------------------- + + utils.show_trace(function() + local variables_1_2 = { + user_str = 'user_str_b', + user_num = 12, + first_name = 'non-existent', + } + local result = gql_query_1:execute(variables_1_2) + results = results .. print_and_return(format_result( + '1_2', query_1, variables_1_2, result)) end) -- select top-level objects by a partial compound primary key (or maybe use @@ -225,23 +246,54 @@ function compound_index_testdata.run_queries(gql_wrapper) -- ------------------------------------------------------------------------ utils.show_trace(function() - local variables_1_2 = {user_num = 12} - local result = gql_query_1:execute(variables_1_2) - results = results .. print_and_return( - ('RESULT\n%s'):format(yaml.encode(result))) + local variables_1_3 = {user_num = 12} + local result = gql_query_1:execute(variables_1_3) + results = results .. print_and_return(format_result( + '1_3', query_1, variables_1_3, result)) + end) + + utils.show_trace(function() + local variables_1_4 = {user_str = 'user_str_b'} + local result = gql_query_1:execute(variables_1_4) + results = results .. print_and_return(format_result( + '1_4', query_1, variables_1_4, result)) + end) + + -- select top-level objects by a partial compound primary key plus filter + -- (or maybe use fullscan) + -- ---------------------------------------------------------------------- + + utils.show_trace(function() + local variables_1_5 = { + user_num = 12, + first_name = 'non-existent' + } + local result = gql_query_1:execute(variables_1_5) + results = results .. print_and_return(format_result( + '1_5', query_1, variables_1_5, result)) + end) + + utils.show_trace(function() + local variables_1_6 = { + user_str = 'user_str_b', + first_name = 'non-existent' + } + local result = gql_query_1:execute(variables_1_6) + results = results .. print_and_return(format_result( + '1_6', query_1, variables_1_6, result)) end) -- select objects by a connection by a full compound index -- ------------------------------------------------------- local query_2 = [[ - query users($user_str: String, $user_num: Long) { + query users($user_str: String, $user_num: Long, $description: String) { user_collection(user_str: $user_str, user_num: $user_num) { user_str user_num last_name first_name - order_connection { + order_connection(description: $description) { order_str order_num description @@ -250,12 +302,27 @@ function compound_index_testdata.run_queries(gql_wrapper) } ]] + local gql_query_2 = gql_wrapper:compile(query_2) + + utils.show_trace(function() + local variables_2_1 = {user_str = 'user_str_b', user_num = 12} + local result = gql_query_2:execute(variables_2_1) + results = results .. print_and_return(format_result( + '2_1', query_2, variables_2_1, result)) + end) + + -- select objects by a connection by a full compound index plus filter + -- ------------------------------------------------------------------- + utils.show_trace(function() - local gql_query_2 = gql_wrapper:compile(query_2) - local variables_2 = {user_str = 'user_str_b', user_num = 12} - local result = gql_query_2:execute(variables_2) - results = results .. print_and_return( - ('RESULT\n%s'):format(yaml.encode(result))) + local variables_2_2 = { + user_str = 'user_str_b', + user_num = 12, + description = 'non-existent', + } + local result = gql_query_2:execute(variables_2_2) + results = results .. print_and_return(format_result( + '2_2', query_2, variables_2_2, result)) end) -- select object by a connection by a partial compound index @@ -281,8 +348,8 @@ function compound_index_testdata.run_queries(gql_wrapper) local gql_query_3 = gql_wrapper:compile(query_3) local variables_3 = {user_str = 'user_str_b', user_num = 12} local result = gql_query_3:execute(variables_3) - results = results .. print_and_return( - ('RESULT\n%s'):format(yaml.encode(result))) + results = results .. print_and_return(format_result( + '3', query_3, variables_3, result)) end) -- offset on top-level by a full compound primary key @@ -310,27 +377,28 @@ function compound_index_testdata.run_queries(gql_wrapper) } } local result = gql_query_4:execute(variables_4_1) - results = results .. print_and_return( - ('RESULT\n%s'):format(yaml.encode(result))) + results = results .. print_and_return(format_result( + '4_1', query_4, variables_4_1, result)) end) -- offset on top-level by a partial compound primary key (expected to fail) -- ------------------------------------------------------------------------ - local ok, err = pcall(function() - local variables_4_2 = { - limit = 10, - offset = { - user_str = 'user_str_b', - } + local variables_4_2 = { + limit = 10, + offset = { + user_str = 'user_str_b', } + } + local ok, err = pcall(function() local result = gql_query_4:execute(variables_4_2) - results = results .. print_and_return( - ('RESULT\n%s'):format(yaml.encode(result))) + results = results .. print_and_return(format_result( + '4_2', query_4, variables_4_2, result)) end) - results = results .. print_and_return( - ('RESULT: ok: %s; err: %s'):format(tostring(ok), strip_error(err))) + local result = {ok = ok, err = strip_error(err)} + results = results .. print_and_return(format_result( + '4_2', query_4, variables_4_2, result)) -- offset when using a connection by a full compound primary key -- ------------------------------------------------------------- @@ -365,30 +433,31 @@ function compound_index_testdata.run_queries(gql_wrapper) } } local result = gql_query_5:execute(variables_5_1) - results = results .. print_and_return( - ('RESULT\n%s'):format(yaml.encode(result))) + results = results .. print_and_return(format_result( + '5_1', query_5, variables_5_1, result)) end) -- offset when using a connection by a partial compound primary key -- (expected to fail) -- ---------------------------------------------------------------- - local ok, err = pcall(function() - local variables_5_2 = { - user_str = 'user_str_b', - user_num = 12, - limit = 4, - offset = { - order_str = 'order_str_b_2', - } + local variables_5_2 = { + user_str = 'user_str_b', + user_num = 12, + limit = 4, + offset = { + order_str = 'order_str_b_2', } + } + local ok, err = pcall(function() local result = gql_query_5:execute(variables_5_2) - results = results .. print_and_return( - ('RESULT\n%s'):format(yaml.encode(result))) + results = results .. print_and_return(format_result( + '5_2', query_5, variables_5_2, result)) end) - results = results .. print_and_return( - ('RESULT: ok: %s; err: %s'):format(tostring(ok), strip_error(err))) + local result = {ok = ok, err = strip_error(err)} + results = results .. print_and_return(format_result( + '5_2', query_5, variables_5_2, result)) return results end