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:
2
5
---
3
6
--- open_set = {
4
7
--- prepared_object_list = <...>,
51
54
--- value = <...>,
52
55
--- },
53
56
--- ...
54
- --- }
57
+ --- },
58
+ --- coerced_arguments = <...>,
55
59
--- },
56
60
--- ...
57
61
--- }
63
67
64
68
local utils = require (' graphql.utils' )
65
69
local core_util = require (' graphql.core.util' )
70
+ local core_types = require (' graphql.core.types' )
66
71
local core_query_util = require (' graphql.core.query_util' )
67
72
local core_validate_variables = require (' graphql.core.validate_variables' )
68
73
local core_introspection = require (' graphql.core.introspection' )
@@ -73,22 +78,17 @@ local accessor_shard_cache = require('graphql.accessor_shard_cache')
73
78
74
79
local bfs_executor = {}
75
80
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
-
86
81
local function get_argument_values (field_type , selection , variables )
87
82
local args = {}
83
+ for argument_name , value in pairs (selection .coerced_arguments or {}) do
84
+ args [argument_name ] = value
85
+ end
88
86
for _ , argument in ipairs (selection .arguments or {}) do
89
87
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 ))
92
92
local value = core_util .coerceValue (argument .value , argument_type ,
93
93
variables , {strict_non_null = true })
94
94
args [argument_name ] = value
@@ -207,33 +207,65 @@ local function filter_object(object, object_type, selections, opts)
207
207
selections = child_selections ,
208
208
}
209
209
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
221
228
}
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
226
258
end
227
259
end
228
260
-- require('yaml').cfg{encode_use_tostring = true}
229
261
-- print('selections')
230
- -- print(require('yaml').encode(res ))
231
- return res
262
+ -- print(require('yaml').encode(selections ))
263
+ return selections
232
264
end
233
265
234
266
if not prepared_resolve .is_calculated then
235
267
local connection_filters = {}
236
- local local_filters = {}
268
+ local local_args = {}
237
269
238
270
local filter = prepared_resolve .prepared_select .filter
239
271
for k , v in pairs (filter ) do
@@ -249,19 +281,23 @@ local function filter_object(object, object_type, selections, opts)
249
281
250
282
for k , v in pairs (args ) do
251
283
if connection_filters [k ] == nil then
252
- local_filters [k ] = v
284
+ local_args [k ] = v
253
285
end
254
286
end
255
287
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
257
294
-- cache_only_prepared_resolve is the same as
258
295
-- prepared_resolve, but it does not require fetching
259
296
-- connected objects to fetch and return this one
260
297
local cache_only_prepared_resolve = field_type .prepare_resolve (
261
- object , local_filters , info )
298
+ object , local_args , info )
262
299
local cache_only_selections = filters_to_selections (
263
- connection_filters )
264
- -- XXX: arguments
300
+ inner_type , filter )
265
301
cache_only_fields_info [field_name ] = {
266
302
is_list = is_list ,
267
303
kind = inner_type ,
@@ -336,7 +372,6 @@ local function invoke_resolve(prepared_object, variables, opts)
336
372
local open_set = {}
337
373
338
374
for field_name , field_info in pairs (prepared_object .fields_info ) do
339
- -- XXX: don't call :invoke() for is_item_cache_only
340
375
local object_or_list
341
376
if field_info .prepared_resolve .is_calculated then
342
377
object_or_list = field_info .prepared_resolve .objs
0 commit comments