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

Commit 38b8504

Browse files
committed
Split prepare and invoke select phases
1 parent 392f08b commit 38b8504

File tree

3 files changed

+218
-133
lines changed

3 files changed

+218
-133
lines changed

graphql/accessor_general.lua

Lines changed: 89 additions & 65 deletions
Original file line numberDiff line numberDiff line change
@@ -922,8 +922,25 @@ local function process_tuple(state, tuple, opts)
922922
return true
923923
end
924924

925-
--- The function is core of this module and implements logic of fetching and
926-
--- filtering requested objects.
925+
--- This function is called on first select related to a query. Its purpose is
926+
--- to initialize qcontext table.
927+
---
928+
--- @tparam table accessor
929+
--- @tparam table qcontext per-query table which stores query internal state;
930+
--- all neccessary initialization of this parameter should be performed by this
931+
--- function
932+
local function init_qcontext(accessor, qcontext)
933+
local settings = accessor.settings
934+
qcontext.statistics = {
935+
resulting_object_cnt = 0,
936+
fetched_object_cnt = 0
937+
}
938+
qcontext.deadline_clock = clock.monotonic64() +
939+
settings.timeout_ms * 1000 * 1000
940+
end
941+
942+
--- The function prepares context for tuples selection, postprocessing and
943+
--- filtering.
927944
---
928945
--- @tparam table self the data accessor created by the `new` function
929946
--- (directly or indirectly using the `accessor_space.new` or the
@@ -943,8 +960,9 @@ end
943960
--- @tparam table extra table which contains extra information related to
944961
--- current select and the whole query
945962
---
946-
--- @treturn table list of matching objects
947-
local function select_internal(self, collection_name, from, filter, args, extra)
963+
--- @treturn table `res` with `request_opts`, `select_state`, `select_opts` and
964+
--- `args` fields
965+
local function prepare_select(self, collection_name, from, filter, args, extra)
948966
assert(type(self) == 'table',
949967
'self must be a table, got ' .. type(self))
950968
assert(type(collection_name) == 'string',
@@ -976,6 +994,12 @@ local function select_internal(self, collection_name, from, filter, args, extra)
976994
assert(args.pcre == nil or type(args.pcre) == 'table',
977995
'args.pcre must be nil or a table, got ' .. type(args.pcre))
978996

997+
-- qcontext initialization
998+
if extra.qcontext.initialized ~= true then
999+
init_qcontext(self, extra.qcontext)
1000+
extra.qcontext.initialized = true
1001+
end
1002+
9791003
local collection = self.collections[collection_name]
9801004
assert(collection ~= nil,
9811005
('cannot find the collection "%s"'):format(
@@ -995,7 +1019,7 @@ local function select_internal(self, collection_name, from, filter, args, extra)
9951019
index_name, collection_name))
9961020
end
9971021

998-
-- lookup functions for unflattening
1022+
-- lookup function for unflattening
9991023
local schema_name = collection.schema_name
10001024
assert(type(schema_name) == 'string',
10011025
'schema_name must be a string, got ' .. type(schema_name))
@@ -1028,18 +1052,15 @@ local function select_internal(self, collection_name, from, filter, args, extra)
10281052
resolveField = extra.resolveField,
10291053
}
10301054

1055+
local iterator_opts = nil
1056+
10311057
if index == nil then
1032-
-- fullscan
1033-
local primary_index = self.funcs.get_primary_index(collection_name)
1034-
for _, tuple in primary_index:pairs() do
1035-
assert(pivot == nil,
1036-
'offset for top-level objects must use a primary index')
1037-
local continue = process_tuple(select_state, tuple, select_opts)
1038-
if not continue then break end
1039-
end
1058+
assert(pivot == nil,
1059+
'offset for top-level objects must use a primary index')
1060+
index = self.funcs.get_primary_index(collection_name)
1061+
index_value = nil
10401062
else
1041-
-- select by index
1042-
local iterator_opts = {}
1063+
iterator_opts = iterator_opts or {}
10431064
if pivot ~= nil then
10441065
-- handle case when there is pivot item (offset was passed)
10451066
if pivot.value_list ~= nil then
@@ -1069,23 +1090,51 @@ local function select_internal(self, collection_name, from, filter, args, extra)
10691090
if full_match and args.limit ~= nil then
10701091
iterator_opts.limit = args.limit
10711092
end
1072-
1073-
for _, tuple in index:pairs(index_value, iterator_opts) do
1074-
local continue = process_tuple(select_state, tuple, select_opts)
1075-
if not continue then break end
1076-
end
10771093
end
10781094

1079-
local count = select_state.count
1080-
local objs = select_state.objs
1095+
-- request options can be changed below
1096+
local request_opts = {
1097+
index = index,
1098+
index_value = index_value,
1099+
iterator_opts = iterator_opts,
1100+
}
10811101

1082-
assert(args.limit == nil or count <= args.limit,
1083-
('count[%d] exceeds limit[%s] (before return)'):format(
1084-
count, args.limit))
1085-
assert(#objs == count,
1086-
('count[%d] is not equal to objs count[%d]'):format(count, #objs))
1102+
return {
1103+
request_opts = request_opts,
1104+
select_state = select_state,
1105+
select_opts = select_opts,
1106+
args = args,
1107+
}
1108+
end
10871109

1088-
return objs
1110+
--- XXX
1111+
local function invoke_select(prepared_select)
1112+
local request_opts = prepared_select.request_opts
1113+
local select_state = prepared_select.select_state
1114+
local select_opts = prepared_select.select_opts
1115+
local args = prepared_select.args
1116+
1117+
local index = request_opts.index
1118+
local index_value = request_opts.index_value
1119+
local iterator_opts = request_opts.iterator_opts
1120+
1121+
for _, tuple in index:pairs(index_value, iterator_opts) do
1122+
local continue = process_tuple(select_state, tuple,
1123+
select_opts)
1124+
if not continue then break end
1125+
end
1126+
1127+
local count = select_state.count
1128+
local objs = select_state.objs
1129+
1130+
assert(args.limit == nil or count <= args.limit,
1131+
('count[%d] exceeds limit[%s] (before return)'):format(
1132+
count, args.limit))
1133+
assert(#objs == count,
1134+
('count[%d] is not equal to objs count[%d]'):format(
1135+
count, #objs))
1136+
1137+
return objs
10891138
end
10901139

10911140
--- Set of asserts to check the `funcs` argument of the @{accessor_general.new}
@@ -1110,22 +1159,6 @@ local function validate_funcs(funcs)
11101159
type(funcs.unflatten_tuple))
11111160
end
11121161

1113-
--- This function is called on first select related to a query. Its purpose is
1114-
--- to initialize qcontext table.
1115-
--- @tparam table accessor
1116-
--- @tparam table qcontext per-query table which stores query internal state;
1117-
--- all neccessary initialization of this parameter should be performed by this
1118-
-- function
1119-
local function init_qcontext(accessor, qcontext)
1120-
local settings = accessor.settings
1121-
qcontext.statistics = {
1122-
resulting_object_cnt = 0,
1123-
fetched_object_cnt = 0
1124-
}
1125-
qcontext.deadline_clock = clock.monotonic64() +
1126-
settings.timeout_ms * 1000 * 1000
1127-
end
1128-
11291162
--- Get an avro-schema for a primary key by a collection name.
11301163
---
11311164
--- @tparam table self accessor_general instance
@@ -1273,9 +1306,8 @@ end
12731306
--- ...
12741307
--- }
12751308
---
1276-
--- @treturn table data accessor instance, a table with the two methods
1277-
--- (`select` and `arguments`) as described in the @{tarantool_graphql.new}
1278-
--- function description.
1309+
--- @treturn table data accessor instance, a table with the methods as
1310+
--- described in the @{tarantool_graphql.new} function description.
12791311
function accessor_general.new(opts, funcs)
12801312
assert(type(opts) == 'table',
12811313
'opts must be a table, got ' .. type(opts))
@@ -1352,26 +1384,18 @@ function accessor_general.new(opts, funcs)
13521384
__index = {
13531385
select = function(self, parent, collection_name, from,
13541386
filter, args, extra)
1355-
assert(type(parent) == 'table',
1356-
'parent must be a table, got ' .. type(parent))
1357-
assert(from == nil or type(from) == 'table',
1358-
'from must be nil or a string, got ' .. type(from))
1359-
assert(from == nil or type(from.collection_name) == 'string',
1360-
'from must be nil or from.collection_name ' ..
1361-
'must be a string, got ' ..
1362-
type((from or {}).collection_name))
1363-
assert(from == nil or type(from.connection_name) == 'string',
1364-
'from must be nil or from.connection_name ' ..
1365-
'must be a string, got ' ..
1366-
type((from or {}).connection_name))
1367-
--`qcontext` initialization
1368-
if extra.qcontext.initialized ~= true then
1369-
init_qcontext(self, extra.qcontext)
1370-
extra.qcontext.initialized = true
1371-
end
1372-
return select_internal(self, collection_name, from, filter,
1387+
local prepared_select = prepare_select(self, collection_name,
1388+
from, filter, args, extra)
1389+
return invoke_select(prepared_select)
1390+
end,
1391+
prepare_select = function(self, parent, collection_name, from,
1392+
filter, args, extra)
1393+
return prepare_select(self, collection_name, from, filter,
13731394
args, extra)
13741395
end,
1396+
invoke_select = function(self, prepared_select)
1397+
return invoke_select(prepared_select)
1398+
end,
13751399
list_args = function(self, collection_name)
13761400
local offset_type = get_primary_key_type(self, collection_name)
13771401

graphql/core/types.lua

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -112,7 +112,9 @@ function initFields(kind, fields)
112112
description = field.description,
113113
deprecationReason = field.deprecationReason,
114114
arguments = field.arguments or {},
115-
resolve = kind == 'Object' and field.resolve or nil
115+
resolve = kind == 'Object' and field.resolve or nil,
116+
prepare_resolve = kind == 'Object' and field.prepare_resolve or nil,
117+
invoke_resolve = kind == 'Object' and field.invoke_resolve or nil,
116118
}
117119
end
118120

0 commit comments

Comments
 (0)