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

Commit 7213b99

Browse files
committed
Hold collection-local arguments in cache requests
It is primarily for filters over 1:N connection borders (#94).
1 parent b063ba2 commit 7213b99

File tree

2 files changed

+75
-39
lines changed

2 files changed

+75
-39
lines changed

graphql/accessor_shard_cache.lua

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -52,7 +52,7 @@ function accessor_shard_cache.fetch(batches)
5252
if next(ids) == nil then
5353
goto continue
5454
end
55-
--print('fetch ids: ' .. require('yaml').encode(ids))
55+
-- print('fetch ids: ' .. require('yaml').encode(ids))
5656
-- local buffers = {}
5757
local results = {}
5858

@@ -101,6 +101,7 @@ function accessor_shard_cache.fetch(batches)
101101
assert(#results == #ids, 'XXX') -- XXX
102102
for i = 1, #ids do
103103
if cache[ids[i]] == nil then
104+
-- print('fetch: ' .. require('json').encode(ids[i]))
104105
cache[ids[i]] = {
105106
result = results[i],
106107
fetch_ids = {fetch_id}

graphql/bfs_executor.lua

Lines changed: 73 additions & 38 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,7 @@
1-
--- XXX
1+
--- Breadth-first executor with support of batching similar requests.
2+
---
3+
--- The main data structure of this module is the list of requests to be
4+
--- processed:
25
---
36
--- open_set = {
47
--- prepared_object_list = <...>,
@@ -51,7 +54,8 @@
5154
--- value = <...>,
5255
--- },
5356
--- ...
54-
--- }
57+
--- },
58+
--- coerced_arguments = <...>,
5559
--- },
5660
--- ...
5761
--- }
@@ -63,6 +67,7 @@
6367

6468
local utils = require('graphql.utils')
6569
local core_util = require('graphql.core.util')
70+
local core_types = require('graphql.core.types')
6671
local core_query_util = require('graphql.core.query_util')
6772
local core_validate_variables = require('graphql.core.validate_variables')
6873
local core_introspection = require('graphql.core.introspection')
@@ -73,22 +78,17 @@ local accessor_shard_cache = require('graphql.accessor_shard_cache')
7378

7479
local bfs_executor = {}
7580

76-
--- XXX
77-
local function get_argument_type(field_type, argument_name)
78-
for name, argument_type in pairs(field_type.arguments) do
79-
if name == argument_name then
80-
return argument_type
81-
end
82-
end
83-
error(('cannot find argument "%s"'):format(argument_name))
84-
end
85-
8681
local function get_argument_values(field_type, selection, variables)
8782
local args = {}
83+
for argument_name, value in pairs(selection.coerced_arguments or {}) do
84+
args[argument_name] = value
85+
end
8886
for _, argument in ipairs(selection.arguments or {}) do
8987
local argument_name = argument.name.value
90-
assert(argument_name ~= nil)
91-
local argument_type = get_argument_type(field_type, argument_name)
88+
assert(argument_name ~= nil, 'argument_name must not be nil')
89+
local argument_type = field_type.arguments[argument_name]
90+
assert(argument_type ~= nil,
91+
('cannot find argument "%s"'):format(argument_name))
9292
local value = core_util.coerceValue(argument.value, argument_type,
9393
variables, {strict_non_null = true})
9494
args[argument_name] = value
@@ -207,33 +207,65 @@ local function filter_object(object, object_type, selections, opts)
207207
selections = child_selections,
208208
}
209209

210-
local function filters_to_selections(connection_filters)
211-
-- XXX: add arguments (important for offset, limit and so on)
212-
local res = {}
213-
for k, v in pairs(connection_filters) do
214-
table.insert(res, {
215-
name = {
216-
value = k
217-
},
218-
kind = 'field',
219-
selectionSet = {
220-
selections = {},
210+
local function filters_to_selections(object_type, filters)
211+
local selections = {}
212+
for k, v in pairs(filters) do
213+
local field_type = object_type.fields[k]
214+
assert(field_type ~= nil, 'fild_type must not be nil')
215+
if field_type.prepare_resolve ~= nil then
216+
-- per-connection field
217+
assert(type(v) == 'table',
218+
'per-connection field filter must be a table, ' ..
219+
'got ' .. type(v))
220+
221+
local new_selection = {
222+
name = {
223+
value = k
224+
},
225+
kind = 'field',
226+
-- selectionSet is nil
227+
-- coerced_arguments is nil
221228
}
222-
})
223-
if type(v) == 'table' then
224-
res[#res].selectionSet.selections =
225-
filters_to_selections(v)
229+
table.insert(selections, new_selection)
230+
231+
local inner_type = core_types.bare(field_type.kind)
232+
local child_selections = filters_to_selections(
233+
inner_type, v)
234+
if next(child_selections) ~= nil then
235+
new_selection.selectionSet = {}
236+
new_selection.selectionSet.selections =
237+
child_selections
238+
end
239+
240+
-- add arguments on local collection fields
241+
for child_k, child_v in pairs(v) do
242+
local is_sel_found = false
243+
for _, sel in ipairs(child_selections) do
244+
if sel.name.value == child_k then
245+
is_sel_found = true
246+
end
247+
end
248+
if not is_sel_found then
249+
if new_selection.coerced_arguments == nil then
250+
new_selection.coerced_arguments = {}
251+
end
252+
assert(new_selection
253+
.coerced_arguments[child_k] == nil,
254+
'found two selections with the same name')
255+
new_selection.coerced_arguments[child_k] = child_v
256+
end
257+
end
226258
end
227259
end
228260
--require('yaml').cfg{encode_use_tostring = true}
229261
--print('selections')
230-
--print(require('yaml').encode(res))
231-
return res
262+
--print(require('yaml').encode(selections))
263+
return selections
232264
end
233265

234266
if not prepared_resolve.is_calculated then
235267
local connection_filters = {}
236-
local local_filters = {}
268+
local local_args = {}
237269

238270
local filter = prepared_resolve.prepared_select.filter
239271
for k, v in pairs(filter) do
@@ -249,19 +281,23 @@ local function filter_object(object, object_type, selections, opts)
249281

250282
for k, v in pairs(args) do
251283
if connection_filters[k] == nil then
252-
local_filters[k] = v
284+
local_args[k] = v
253285
end
254286
end
255287

256-
if next(connection_filters) ~= nil then
288+
-- create cache only requests for requests with 'by connection'
289+
-- filters and without extra arguments (like mutation arguments)
290+
local extra_args = prepared_resolve.prepared_select.extra
291+
.extra_args or {}
292+
if next(connection_filters) ~= nil and
293+
next(extra_args) == nil then
257294
-- cache_only_prepared_resolve is the same as
258295
-- prepared_resolve, but it does not require fetching
259296
-- connected objects to fetch and return this one
260297
local cache_only_prepared_resolve = field_type.prepare_resolve(
261-
object, local_filters, info)
298+
object, local_args, info)
262299
local cache_only_selections = filters_to_selections(
263-
connection_filters)
264-
-- XXX: arguments
300+
inner_type, filter)
265301
cache_only_fields_info[field_name] = {
266302
is_list = is_list,
267303
kind = inner_type,
@@ -336,7 +372,6 @@ local function invoke_resolve(prepared_object, variables, opts)
336372
local open_set = {}
337373

338374
for field_name, field_info in pairs(prepared_object.fields_info) do
339-
-- XXX: don't call :invoke() for is_item_cache_only
340375
local object_or_list
341376
if field_info.prepared_resolve.is_calculated then
342377
object_or_list = field_info.prepared_resolve.objs

0 commit comments

Comments
 (0)