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

Commit 50bb3c4

Browse files
committed
Split prepare and invoke select phases
1 parent 087502a commit 50bb3c4

File tree

4 files changed

+156
-69
lines changed

4 files changed

+156
-69
lines changed

graphql/accessor_general.lua

Lines changed: 101 additions & 56 deletions
Original file line numberDiff line numberDiff line change
@@ -975,8 +975,8 @@ local function perform_primary_key_operation(self, collection_name, schema_name,
975975
return new_objects
976976
end
977977

978-
--- The function is core of this module and implements logic of fetching and
979-
--- filtering requested objects.
978+
--- The function prepares context for tuples selection, postprocessing and
979+
--- filtering.
980980
---
981981
--- @tparam table self the data accessor created by the `new` function
982982
--- (directly or indirectly using the `accessor_space.new` or the
@@ -996,8 +996,10 @@ end
996996
--- @tparam table extra table which contains extra information related to
997997
--- current select and the whole query
998998
---
999-
--- @treturn table list of matching objects
1000-
local function select_internal(self, collection_name, from, filter, args, extra)
999+
--- @treturn table `res` with `request_opts`, `select_state`, `select_opts` and
1000+
--- `args` fields
1001+
local function prepare_select_internal(self, collection_name, from, filter,
1002+
args, extra)
10011003
check(self, 'self', 'table')
10021004
check(collection_name, 'collection_name', 'string')
10031005
check(from, 'from', 'table')
@@ -1028,7 +1030,7 @@ local function select_internal(self, collection_name, from, filter, args, extra)
10281030
index_name, collection_name))
10291031
end
10301032

1031-
-- lookup functions for unflattening
1033+
-- lookup function for unflattening
10321034
local schema_name = collection.schema_name
10331035
assert(type(schema_name) == 'string',
10341036
'schema_name must be a string, got ' .. type(schema_name))
@@ -1075,27 +1077,17 @@ local function select_internal(self, collection_name, from, filter, args, extra)
10751077
pivot.filter ~= nil), err)
10761078
end
10771079

1078-
if index == nil then
1079-
-- fullscan
1080-
local primary_index = self.funcs.get_primary_index(self,
1081-
collection_name)
1082-
1083-
-- count full scan select request
1084-
qcontext.statistics.select_requests_cnt =
1085-
qcontext.statistics.select_requests_cnt + 1
1086-
qcontext.statistics.full_scan_select_requests_cnt =
1087-
qcontext.statistics.full_scan_select_requests_cnt + 1
1080+
local iterator_opts = nil
1081+
local is_full_scan
10881082

1089-
for _, tuple in primary_index:pairs() do
1090-
assert(pivot == nil,
1091-
'offset for top-level objects must use a primary index')
1092-
local continue = process_tuple(self, select_state, tuple,
1093-
select_opts)
1094-
if not continue then break end
1095-
end
1083+
if index == nil then
1084+
assert(pivot == nil,
1085+
'offset for top-level objects must use a primary index')
1086+
index = self.funcs.get_primary_index(self, collection_name)
1087+
index_value = nil
1088+
is_full_scan = true
10961089
else
1097-
-- select by index
1098-
local iterator_opts = {}
1090+
iterator_opts = iterator_opts or {}
10991091
if pivot ~= nil then
11001092
-- handle case when there is pivot item (offset was passed)
11011093
if pivot.value_list ~= nil then
@@ -1126,33 +1118,80 @@ local function select_internal(self, collection_name, from, filter, args, extra)
11261118
iterator_opts.limit = args.limit
11271119
end
11281120

1129-
local tuple_count = 0
1121+
is_full_scan = false
1122+
end
1123+
1124+
-- request options can be changed below
1125+
local request_opts = {
1126+
index = index,
1127+
index_value = index_value,
1128+
iterator_opts = iterator_opts,
1129+
is_full_scan = is_full_scan,
1130+
}
11301131

1132+
return {
1133+
request_opts = request_opts,
1134+
select_state = select_state,
1135+
select_opts = select_opts,
1136+
collection_name = collection_name,
1137+
from = from,
1138+
filter = filter,
1139+
args = args,
1140+
extra = extra,
1141+
}
1142+
end
1143+
1144+
--- XXX
1145+
local function invoke_select_internal(self, prepared_select)
1146+
local request_opts = prepared_select.request_opts
1147+
local select_state = prepared_select.select_state
1148+
local select_opts = prepared_select.select_opts
1149+
local args = prepared_select.args
1150+
local extra = prepared_select.extra
1151+
1152+
local index = request_opts.index
1153+
local index_value = request_opts.index_value
1154+
local iterator_opts = request_opts.iterator_opts
1155+
local is_full_scan = request_opts.is_full_scan
1156+
1157+
local qcontext = extra.qcontext
1158+
1159+
-- count all select request
1160+
qcontext.statistics.select_requests_cnt =
1161+
qcontext.statistics.select_requests_cnt + 1
1162+
1163+
if is_full_scan then
1164+
-- count full scan select request
1165+
qcontext.statistics.full_scan_select_requests_cnt =
1166+
qcontext.statistics.full_scan_select_requests_cnt + 1
1167+
else
11311168
-- count index select request
1132-
qcontext.statistics.select_requests_cnt =
1133-
qcontext.statistics.select_requests_cnt + 1
11341169
qcontext.statistics.index_select_requests_cnt =
11351170
qcontext.statistics.index_select_requests_cnt + 1
1171+
end
11361172

1137-
for _, tuple in index:pairs(index_value, iterator_opts) do
1138-
tuple_count = tuple_count + 1
1139-
-- check full match constraint
1140-
if extra.exp_tuple_count ~= nil and
1141-
tuple_count > extra.exp_tuple_count then
1142-
error(('FULL MATCH constraint was failed: we got more then ' ..
1143-
'%d tuples'):format(extra.exp_tuple_count))
1144-
end
1145-
local continue = process_tuple(self, select_state, tuple,
1146-
select_opts)
1147-
if not continue then break end
1148-
end
1173+
local tuple_count = 0
1174+
1175+
for _, tuple in index:pairs(index_value, iterator_opts) do
1176+
tuple_count = tuple_count + 1
11491177

11501178
-- check full match constraint
11511179
if extra.exp_tuple_count ~= nil and
1152-
tuple_count ~= extra.exp_tuple_count then
1153-
error(('FULL MATCH constraint was failed: we expect %d tuples, ' ..
1154-
'got %d'):format(extra.exp_tuple_count, tuple_count))
1180+
tuple_count > extra.exp_tuple_count then
1181+
error(('FULL MATCH constraint was failed: we got more then ' ..
1182+
'%d tuples'):format(extra.exp_tuple_count))
11551183
end
1184+
1185+
local continue = process_tuple(self, select_state, tuple,
1186+
select_opts)
1187+
if not continue then break end
1188+
end
1189+
1190+
-- check full match constraint
1191+
if extra.exp_tuple_count ~= nil and
1192+
tuple_count ~= extra.exp_tuple_count then
1193+
error(('FULL MATCH constraint was failed: we expect %d tuples, ' ..
1194+
'got %d'):format(extra.exp_tuple_count, tuple_count))
11561195
end
11571196

11581197
local count = select_state.count
@@ -1344,6 +1383,8 @@ end
13441383
--- all neccessary initialization of this parameter should be performed by this
13451384
-- function
13461385
local function init_qcontext(accessor, qcontext)
1386+
if qcontext.initialized then return end
1387+
13471388
for k, v in pairs(accessor.query_settings_default) do
13481389
if qcontext.query_settings[k] == nil then
13491390
qcontext.query_settings[k] = v
@@ -1361,6 +1402,8 @@ local function init_qcontext(accessor, qcontext)
13611402
full_scan_select_requests_cnt = 0,
13621403
index_select_requests_cnt = 0,
13631404
}
1405+
1406+
qcontext.initialized = true
13641407
end
13651408

13661409
--- Create default unflatten/flatten/xflatten functions, that can be called
@@ -1479,9 +1522,8 @@ end
14791522
--- `accessor_space` and the `accessor_shard` modules documentation for these
14801523
--- functions description.
14811524
---
1482-
--- @treturn table data accessor instance, a table with the two methods
1483-
--- (`select` and `arguments`) as described in the @{impl.new} function
1484-
--- description.
1525+
--- @treturn table data accessor instance, a table with the methods as
1526+
--- described in the @{impl.new} function description.
14851527
---
14861528
--- Brief explanation of some select function parameters:
14871529
---
@@ -1572,21 +1614,13 @@ function accessor_general.new(opts, funcs)
15721614
__index = {
15731615
select = function(self, parent, collection_name, from,
15741616
filter, args, extra)
1575-
check(parent, 'parent', 'table')
1576-
validate_from_parameter(from)
1577-
1578-
--`qcontext` initialization
1579-
if extra.qcontext.initialized ~= true then
1580-
init_qcontext(self, extra.qcontext)
1581-
extra.qcontext.initialized = true
1582-
end
1583-
15841617
local inserted = insert_internal(self, collection_name, from,
15851618
filter, args, extra)
15861619
if inserted ~= nil then return inserted end
15871620

1588-
local selected = select_internal(self, collection_name, from, filter,
1589-
args, extra)
1621+
local prepared_select = self:prepare_select(parent,
1622+
collection_name, from, filter, args, extra)
1623+
local selected = self:invoke_select(prepared_select)
15901624

15911625
local updated = update_internal(self, collection_name, extra,
15921626
selected)
@@ -1598,6 +1632,17 @@ function accessor_general.new(opts, funcs)
15981632

15991633
return selected
16001634
end,
1635+
prepare_select = function(self, parent, collection_name, from,
1636+
filter, args, extra)
1637+
check(parent, 'parent', 'table')
1638+
validate_from_parameter(from)
1639+
1640+
init_qcontext(self, extra.qcontext)
1641+
1642+
return prepare_select_internal(self, collection_name, from,
1643+
filter, args, extra)
1644+
end,
1645+
invoke_select = invoke_select_internal,
16011646
}
16021647
})
16031648
end

graphql/convert_schema/resolve.lua

Lines changed: 46 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -83,11 +83,33 @@ local function separate_args_instance(args_instance, arguments)
8383
}
8484
end
8585

86+
local function invoke_resolve(prepared_resolve)
87+
if prepared_resolve.is_calculated then
88+
return prepared_resolve.objs
89+
end
90+
91+
local prepared_select = prepared_resolve.prepared_select
92+
-- local opts = prepared_resolve.opts
93+
local accessor = prepared_resolve.accessor
94+
local c = prepared_resolve.connection
95+
96+
local objs = accessor:invoke_select(prepared_select)
97+
assert(type(objs) == 'table',
98+
'objs list received from an accessor ' ..
99+
'must be a table, got ' .. type(objs))
100+
if c.type == '1:1' then
101+
return objs[1] -- nil for empty list of matching objects
102+
else -- c.type == '1:N'
103+
return objs
104+
end
105+
end
106+
86107
function resolve.gen_resolve_function(collection_name, connection,
87108
destination_type, arguments, accessor, opts)
88109
local c = connection
89110
local opts = opts or {}
90111
local disable_dangling_check = opts.disable_dangling_check or false
112+
local gen_prepare = opts.gen_prepare or false
91113
local bare_destination_type = core_types.bare(destination_type)
92114

93115
-- capture `bare_destination_type`
@@ -141,16 +163,30 @@ function resolve.gen_resolve_function(collection_name, connection,
141163
arguments)
142164
extra.extra_args = arguments_instance.extra
143165

144-
local objs = accessor:select(parent,
145-
c.destination_collection, from,
146-
arguments_instance.object, arguments_instance.list, extra)
147-
assert(type(objs) == 'table',
148-
'objs list received from an accessor ' ..
149-
'must be a table, got ' .. type(objs))
150-
if c.type == '1:1' then
151-
return objs[1] -- nil for empty list of matching objects
152-
else -- c.type == '1:N'
153-
return objs
166+
if gen_prepare then
167+
local prepared_select = accessor:prepare_select(parent,
168+
c.destination_collection, from,
169+
arguments_instance.object, arguments_instance.list, extra)
170+
return {
171+
is_calculated = false,
172+
prepared_select = prepared_select,
173+
-- opts = opts,
174+
accessor = accessor,
175+
connection = c,
176+
invoke = invoke_resolve,
177+
}
178+
else
179+
local objs = accessor:select(parent,
180+
c.destination_collection, from,
181+
arguments_instance.object, arguments_instance.list, extra)
182+
assert(type(objs) == 'table',
183+
'objs list received from an accessor ' ..
184+
'must be a table, got ' .. type(objs))
185+
if c.type == '1:1' then
186+
return objs[1] -- nil for empty list of matching objects
187+
else -- c.type == '1:N'
188+
return objs
189+
end
154190
end
155191
end
156192
end

graphql/convert_schema/types.lua

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -158,14 +158,18 @@ local function convert_simple_connection(state, connection, collection_name)
158158
local opts = {
159159
disable_dangling_check = state.disable_dangling_check,
160160
}
161-
local resolve_function = resolve.gen_resolve_function(collection_name, c,
162-
destination_type, arguments, state.accessor, opts)
161+
local resolve_function = resolve.gen_resolve_function(
162+
collection_name, c, destination_type, arguments, state.accessor, opts)
163+
opts.gen_prepare = true
164+
local prepare_resolve_function = resolve.gen_resolve_function(
165+
collection_name, c, destination_type, arguments, state.accessor, opts)
163166

164167
local field = {
165168
name = c.name,
166169
kind = destination_type,
167170
arguments = c_args,
168171
resolve = resolve_function,
172+
prepare_resolve = prepare_resolve_function,
169173
}
170174

171175
return field

graphql/core/types.lua

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -132,7 +132,9 @@ function initFields(kind, fields)
132132
description = field.description,
133133
deprecationReason = field.deprecationReason,
134134
arguments = field.arguments or {},
135-
resolve = kind == 'Object' and field.resolve or nil
135+
resolve = kind == 'Object' and field.resolve or nil,
136+
prepare_resolve = kind == 'Object' and field.prepare_resolve or nil,
137+
invoke_resolve = kind == 'Object' and field.invoke_resolve or nil,
136138
}
137139
end
138140

0 commit comments

Comments
 (0)