graphql 2.3.3 → 2.3.5

Sign up to get free protection for your applications and to get access to all the features.
Files changed (33) hide show
  1. checksums.yaml +4 -4
  2. data/lib/generators/graphql/install/mutation_root_generator.rb +2 -2
  3. data/lib/graphql/analysis/ast/query_complexity.rb +1 -1
  4. data/lib/graphql/dataloader/async_dataloader.rb +1 -0
  5. data/lib/graphql/dataloader/null_dataloader.rb +1 -1
  6. data/lib/graphql/dataloader.rb +6 -3
  7. data/lib/graphql/execution/interpreter/runtime/graphql_result.rb +7 -4
  8. data/lib/graphql/execution/interpreter/runtime.rb +52 -63
  9. data/lib/graphql/execution/interpreter.rb +1 -1
  10. data/lib/graphql/language/nodes.rb +60 -26
  11. data/lib/graphql/language/parser.rb +56 -15
  12. data/lib/graphql/query.rb +2 -2
  13. data/lib/graphql/rubocop/graphql/base_cop.rb +1 -1
  14. data/lib/graphql/schema/addition.rb +21 -11
  15. data/lib/graphql/schema/has_single_input_argument.rb +1 -0
  16. data/lib/graphql/schema/input_object.rb +1 -0
  17. data/lib/graphql/schema/introspection_system.rb +2 -2
  18. data/lib/graphql/schema/late_bound_type.rb +4 -0
  19. data/lib/graphql/schema/list.rb +2 -2
  20. data/lib/graphql/schema/member/has_arguments.rb +2 -35
  21. data/lib/graphql/schema/member/has_directives.rb +1 -1
  22. data/lib/graphql/schema/member/relay_shortcuts.rb +1 -1
  23. data/lib/graphql/schema/member/type_system_helpers.rb +1 -2
  24. data/lib/graphql/schema/warden.rb +2 -3
  25. data/lib/graphql/schema.rb +20 -20
  26. data/lib/graphql/static_validation/rules/fields_will_merge.rb +1 -1
  27. data/lib/graphql/subscriptions/action_cable_subscriptions.rb +1 -1
  28. data/lib/graphql/tracing/prometheus_trace.rb +8 -8
  29. data/lib/graphql/tracing/sentry_trace.rb +10 -10
  30. data/lib/graphql/type_kinds.rb +1 -1
  31. data/lib/graphql/version.rb +1 -1
  32. data/lib/graphql.rb +0 -8
  33. metadata +2 -2
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: d1511256e7812b5c2de2a01ffa44f8a77f2e8959837344eaf1c8780d0b1bf700
4
- data.tar.gz: 87a0734b541d8f2cbbd3fb293a63663cbc57c61e6ab39242449596c6ca759442
3
+ metadata.gz: e5f20ae656aec8f5ad77a6edd73103d2f5a25511ae3c9b515c5b0c58ecc91cac
4
+ data.tar.gz: 6b51f66b0f2188c292b34c61e367de84cb37a7894e536b5b8105a95ec60b9c64
5
5
  SHA512:
6
- metadata.gz: fff5ef36d8e8dff310cac664178ebf0e902cd067a893fedd164902625751fe457a070f1daf2a2251d0dd2ec57fb16daccc81b54267048bbb71c027caf7905100
7
- data.tar.gz: 5fc4e6c4a44398e9f77d99c5224d22128a9c80e64a17a156500337b4d658270da9aa7af71f8d06cc065939cc42b41de3e07d66cb7622704ad179424c312dd7a0
6
+ metadata.gz: 96bd289b9d880438ed2c7610b3a7008cb793fd4551191fcf084c0f947c3da195e07f07346e0b2c9b88177fdbeed098591508879756d7f5919c53c9576f5548e8
7
+ data.tar.gz: ce92d82eee23a710b66f3d29bdc29690b2e368f42ddfd60b159708dac0b018024a87bbf6069d8274878e98e0821f223b0cd2fafba41c23afab86dc7faa97328c
@@ -9,7 +9,7 @@ module Graphql
9
9
  class MutationRootGenerator < Rails::Generators::Base
10
10
  include Core
11
11
 
12
- desc "Create mutation base type, mutation root tipe, and adds the latter to the schema"
12
+ desc "Create mutation base type, mutation root type, and adds the latter to the schema"
13
13
  source_root File.expand_path('../templates', __FILE__)
14
14
 
15
15
  class_option :schema,
@@ -31,4 +31,4 @@ module Graphql
31
31
  end
32
32
  end
33
33
  end
34
- end
34
+ end
@@ -12,7 +12,7 @@ module GraphQL
12
12
  @complexities_on_type_by_query = {}
13
13
  end
14
14
 
15
- # Overide this method to use the complexity result
15
+ # Override this method to use the complexity result
16
16
  def result
17
17
  max_possible_complexity
18
18
  end
@@ -77,6 +77,7 @@ module GraphQL
77
77
  set_fiber_variables(fiber_vars)
78
78
  Thread.current[:graphql_dataloader_next_tick] = condition
79
79
  pending_sources.each(&:run_pending_keys)
80
+ cleanup_fiber
80
81
  end
81
82
  end
82
83
  end
@@ -8,7 +8,7 @@ module GraphQL
8
8
  # simple internal code while adding the option to add Dataloader.
9
9
  class NullDataloader < Dataloader
10
10
  # These are all no-ops because code was
11
- # executed sychronously.
11
+ # executed synchronously.
12
12
  def run; end
13
13
  def run_isolated; yield; end
14
14
  def yield
@@ -88,6 +88,11 @@ module GraphQL
88
88
  nil
89
89
  end
90
90
 
91
+ # This method is called when Dataloader is finished using a fiber.
92
+ # Use it to perform any cleanup, such as releasing database connections (if required manually)
93
+ def cleanup_fiber
94
+ end
95
+
91
96
  # Get a Source instance from this dataloader, for calling `.load(...)` or `.request(...)` on.
92
97
  #
93
98
  # @param source_class [Class<GraphQL::Dataloader::Source]
@@ -231,9 +236,7 @@ module GraphQL
231
236
  Fiber.new(blocking: !@nonblocking) {
232
237
  set_fiber_variables(fiber_vars)
233
238
  yield
234
- # With `.transfer`, you have to explicitly pass back to the parent --
235
- # if the fiber is allowed to terminate normally, control is passed to the main fiber instead.
236
- true
239
+ cleanup_fiber
237
240
  }
238
241
  end
239
242
 
@@ -5,7 +5,7 @@ module GraphQL
5
5
  class Interpreter
6
6
  class Runtime
7
7
  module GraphQLResult
8
- def initialize(result_name, result_type, application_value, parent_result, is_non_null_in_parent)
8
+ def initialize(result_name, result_type, application_value, parent_result, is_non_null_in_parent, selections, is_eager)
9
9
  @graphql_parent = parent_result
10
10
  @graphql_application_value = application_value
11
11
  @graphql_result_type = result_type
@@ -16,6 +16,8 @@ module GraphQL
16
16
  @graphql_is_non_null_in_parent = is_non_null_in_parent
17
17
  # Jump through some hoops to avoid creating this duplicate storage if at all possible.
18
18
  @graphql_metadata = nil
19
+ @graphql_selections = selections
20
+ @graphql_is_eager = is_eager
19
21
  end
20
22
 
21
23
  def path
@@ -28,14 +30,15 @@ module GraphQL
28
30
  end
29
31
 
30
32
  attr_accessor :graphql_dead
31
- attr_reader :graphql_parent, :graphql_result_name, :graphql_is_non_null_in_parent, :graphql_application_value, :graphql_result_type
33
+ attr_reader :graphql_parent, :graphql_result_name, :graphql_is_non_null_in_parent,
34
+ :graphql_application_value, :graphql_result_type, :graphql_selections, :graphql_is_eager
32
35
 
33
36
  # @return [Hash] Plain-Ruby result data (`@graphql_metadata` contains Result wrapper objects)
34
37
  attr_accessor :graphql_result_data
35
38
  end
36
39
 
37
40
  class GraphQLResultHash
38
- def initialize(_result_name, _result_type, _application_value, _parent_result, _is_non_null_in_parent)
41
+ def initialize(_result_name, _result_type, _application_value, _parent_result, _is_non_null_in_parent, _selections, _is_eager)
39
42
  super
40
43
  @graphql_result_data = {}
41
44
  end
@@ -123,7 +126,7 @@ module GraphQL
123
126
  class GraphQLResultArray
124
127
  include GraphQLResult
125
128
 
126
- def initialize(_result_name, _result_type, _application_value, _parent_result, _is_non_null_in_parent)
129
+ def initialize(_result_name, _result_type, _application_value, _parent_result, _is_non_null_in_parent, _selections, _is_eager)
127
130
  super
128
131
  @graphql_result_data = []
129
132
  end
@@ -65,16 +65,6 @@ module GraphQL
65
65
  "#<#{self.class.name} response=#{@response.inspect}>"
66
66
  end
67
67
 
68
- def tap_or_each(obj_or_array)
69
- if obj_or_array.is_a?(Array)
70
- obj_or_array.each do |item|
71
- yield(item, true)
72
- end
73
- else
74
- yield(obj_or_array, false)
75
- end
76
- end
77
-
78
68
  # This _begins_ the execution. Some deferred work
79
69
  # might be stored up in lazies.
80
70
  # @return [void]
@@ -84,7 +74,8 @@ module GraphQL
84
74
  root_type = schema.root_type_for_operation(root_op_type)
85
75
  runtime_object = root_type.wrap(query.root_value, context)
86
76
  runtime_object = schema.sync_lazy(runtime_object)
87
- @response = GraphQLResultHash.new(nil, root_type, runtime_object, nil, false)
77
+ is_eager = root_op_type == "mutation"
78
+ @response = GraphQLResultHash.new(nil, root_type, runtime_object, nil, false, root_operation.selections, is_eager)
88
79
  st = get_current_runtime_state
89
80
  st.current_result = @response
90
81
 
@@ -93,17 +84,9 @@ module GraphQL
93
84
  @response = nil
94
85
  else
95
86
  call_method_on_directives(:resolve, runtime_object, root_operation.directives) do # execute query level directives
96
- gathered_selections = gather_selections(runtime_object, root_type, root_operation.selections)
97
- # This is kind of a hack -- `gathered_selections` is an Array if any of the selections
98
- # require isolation during execution (because of runtime directives). In that case,
99
- # make a new, isolated result hash for writing the result into. (That isolated response
100
- # is eventually merged back into the main response)
101
- #
102
- # Otherwise, `gathered_selections` is a hash of selections which can be
103
- # directly evaluated and the results can be written right into the main response hash.
104
- tap_or_each(gathered_selections) do |selections, is_selection_array|
87
+ each_gathered_selections(@response) do |selections, is_selection_array|
105
88
  if is_selection_array
106
- selection_response = GraphQLResultHash.new(nil, root_type, runtime_object, nil, false)
89
+ selection_response = GraphQLResultHash.new(nil, root_type, runtime_object, nil, false, selections, is_eager)
107
90
  final_response = @response
108
91
  else
109
92
  selection_response = @response
@@ -112,12 +95,10 @@ module GraphQL
112
95
 
113
96
  @dataloader.append_job {
114
97
  evaluate_selections(
115
- root_op_type == "mutation",
116
98
  selections,
117
99
  selection_response,
118
100
  final_response,
119
101
  nil,
120
- nil,
121
102
  )
122
103
  }
123
104
  end
@@ -126,8 +107,18 @@ module GraphQL
126
107
  nil
127
108
  end
128
109
 
129
- def gather_selections(owner_object, owner_type, selections, selections_to_run = nil, selections_by_name = {})
110
+ def each_gathered_selections(response_hash)
111
+ gathered_selections = gather_selections(response_hash.graphql_application_value, response_hash.graphql_result_type, response_hash.graphql_selections)
112
+ if gathered_selections.is_a?(Array)
113
+ gathered_selections.each do |item|
114
+ yield(item, true)
115
+ end
116
+ else
117
+ yield(gathered_selections, false)
118
+ end
119
+ end
130
120
 
121
+ def gather_selections(owner_object, owner_type, selections, selections_to_run = nil, selections_by_name = {})
131
122
  selections.each do |node|
132
123
  # Skip gathering this if the directive says so
133
124
  if !directives_include?(node, owner_object, owner_type)
@@ -139,7 +130,7 @@ module GraphQL
139
130
  selections = selections_by_name[response_key]
140
131
  # if there was already a selection of this field,
141
132
  # use an array to hold all selections,
142
- # otherise, use the single node to represent the selection
133
+ # otherwise, use the single node to represent the selection
143
134
  if selections
144
135
  # This field was already selected at least once,
145
136
  # add this node to the list of selections
@@ -172,17 +163,26 @@ module GraphQL
172
163
  type_defn = schema.get_type(node.type.name, context)
173
164
 
174
165
  if query.warden.possible_types(type_defn).include?(owner_type)
175
- gather_selections(owner_object, owner_type, node.selections, selections_to_run, next_selections)
166
+ result = gather_selections(owner_object, owner_type, node.selections, selections_to_run, next_selections)
167
+ if !result.equal?(next_selections)
168
+ selections_to_run = result
169
+ end
176
170
  end
177
171
  else
178
172
  # it's an untyped fragment, definitely continue
179
- gather_selections(owner_object, owner_type, node.selections, selections_to_run, next_selections)
173
+ result = gather_selections(owner_object, owner_type, node.selections, selections_to_run, next_selections)
174
+ if !result.equal?(next_selections)
175
+ selections_to_run = result
176
+ end
180
177
  end
181
178
  when GraphQL::Language::Nodes::FragmentSpread
182
179
  fragment_def = query.fragments[node.name]
183
180
  type_defn = query.get_type(fragment_def.type.name)
184
181
  if query.warden.possible_types(type_defn).include?(owner_type)
185
- gather_selections(owner_object, owner_type, fragment_def.selections, selections_to_run, next_selections)
182
+ result = gather_selections(owner_object, owner_type, fragment_def.selections, selections_to_run, next_selections)
183
+ if !result.equal?(next_selections)
184
+ selections_to_run = result
185
+ end
186
186
  end
187
187
  else
188
188
  raise "Invariant: unexpected selection class: #{node.class}"
@@ -195,7 +195,7 @@ module GraphQL
195
195
  NO_ARGS = GraphQL::EmptyObjects::EMPTY_HASH
196
196
 
197
197
  # @return [void]
198
- def evaluate_selections(is_eager_selection, gathered_selections, selections_result, target_result, parent_object, runtime_state) # rubocop:disable Metrics/ParameterLists
198
+ def evaluate_selections(gathered_selections, selections_result, target_result, runtime_state) # rubocop:disable Metrics/ParameterLists
199
199
  runtime_state ||= get_current_runtime_state
200
200
  runtime_state.current_result_name = nil
201
201
  runtime_state.current_result = selections_result
@@ -210,7 +210,7 @@ module GraphQL
210
210
  gathered_selections.each do |result_name, field_ast_nodes_or_ast_node|
211
211
  @dataloader.append_job {
212
212
  evaluate_selection(
213
- result_name, field_ast_nodes_or_ast_node, is_eager_selection, selections_result, parent_object
213
+ result_name, field_ast_nodes_or_ast_node, selections_result
214
214
  )
215
215
  finished_jobs += 1
216
216
  if target_result && finished_jobs == enqueued_jobs
@@ -220,7 +220,7 @@ module GraphQL
220
220
  # Field resolution may pause the fiber,
221
221
  # so it wouldn't get to the `Resolve` call that happens below.
222
222
  # So instead trigger a run from this outer context.
223
- if is_eager_selection
223
+ if selections_result.graphql_is_eager
224
224
  @dataloader.clear_cache
225
225
  @dataloader.run
226
226
  @dataloader.clear_cache
@@ -231,7 +231,7 @@ module GraphQL
231
231
  end
232
232
 
233
233
  # @return [void]
234
- def evaluate_selection(result_name, field_ast_nodes_or_ast_node, is_eager_field, selections_result, parent_object) # rubocop:disable Metrics/ParameterLists
234
+ def evaluate_selection(result_name, field_ast_nodes_or_ast_node, selections_result) # rubocop:disable Metrics/ParameterLists
235
235
  return if selections_result.graphql_dead
236
236
  # As a performance optimization, the hash key will be a `Node` if
237
237
  # there's only one selection of the field. But if there are multiple
@@ -258,28 +258,27 @@ module GraphQL
258
258
  owner_object = field_defn.owner.wrap(owner_object, context)
259
259
  end
260
260
 
261
- return_type = field_defn.type
262
261
  if !field_defn.any_arguments?
263
262
  resolved_arguments = GraphQL::Execution::Interpreter::Arguments::EMPTY
264
263
  if field_defn.extras.size == 0
265
264
  evaluate_selection_with_resolved_keyword_args(
266
- NO_ARGS, resolved_arguments, field_defn, ast_node, field_ast_nodes, owner_object, is_eager_field, result_name, selections_result, parent_object, return_type, return_type.non_null?, runtime_state
265
+ NO_ARGS, resolved_arguments, field_defn, ast_node, field_ast_nodes, owner_object, result_name, selections_result, runtime_state
267
266
  )
268
267
  else
269
- evaluate_selection_with_args(resolved_arguments, field_defn, ast_node, field_ast_nodes, owner_object, is_eager_field, result_name, selections_result, parent_object, return_type, runtime_state)
268
+ evaluate_selection_with_args(resolved_arguments, field_defn, ast_node, field_ast_nodes, owner_object, result_name, selections_result, runtime_state)
270
269
  end
271
270
  else
272
271
  @query.arguments_cache.dataload_for(ast_node, field_defn, owner_object) do |resolved_arguments|
273
272
  runtime_state = get_current_runtime_state # This might be in a different fiber
274
- evaluate_selection_with_args(resolved_arguments, field_defn, ast_node, field_ast_nodes, owner_object, is_eager_field, result_name, selections_result, parent_object, return_type, runtime_state)
273
+ evaluate_selection_with_args(resolved_arguments, field_defn, ast_node, field_ast_nodes, owner_object, result_name, selections_result, runtime_state)
275
274
  end
276
275
  end
277
276
  end
278
277
 
279
- def evaluate_selection_with_args(arguments, field_defn, ast_node, field_ast_nodes, object, is_eager_field, result_name, selection_result, parent_object, return_type, runtime_state) # rubocop:disable Metrics/ParameterLists
278
+ def evaluate_selection_with_args(arguments, field_defn, ast_node, field_ast_nodes, object, result_name, selection_result, runtime_state) # rubocop:disable Metrics/ParameterLists
280
279
  after_lazy(arguments, field: field_defn, ast_node: ast_node, owner_object: object, arguments: arguments, result_name: result_name, result: selection_result, runtime_state: runtime_state) do |resolved_arguments, runtime_state|
281
- return_type_non_null = return_type.non_null?
282
280
  if resolved_arguments.is_a?(GraphQL::ExecutionError) || resolved_arguments.is_a?(GraphQL::UnauthorizedError)
281
+ return_type_non_null = field_defn.type.non_null?
283
282
  continue_value(resolved_arguments, field_defn, return_type_non_null, ast_node, result_name, selection_result)
284
283
  next
285
284
  end
@@ -318,7 +317,8 @@ module GraphQL
318
317
  # to the keyword args hash _before_ freezing everything.
319
318
  extra_args[:argument_details] = :__arguments_add_self
320
319
  when :parent
321
- extra_args[:parent] = parent_object
320
+ parent_result = selection_result.graphql_parent
321
+ extra_args[:parent] = parent_result&.graphql_application_value&.object
322
322
  else
323
323
  extra_args[extra] = field_defn.fetch_extra(extra, context)
324
324
  end
@@ -329,11 +329,11 @@ module GraphQL
329
329
  resolved_arguments.keyword_arguments
330
330
  end
331
331
 
332
- evaluate_selection_with_resolved_keyword_args(kwarg_arguments, resolved_arguments, field_defn, ast_node, field_ast_nodes, object, is_eager_field, result_name, selection_result, parent_object, return_type, return_type_non_null, runtime_state)
332
+ evaluate_selection_with_resolved_keyword_args(kwarg_arguments, resolved_arguments, field_defn, ast_node, field_ast_nodes, object, result_name, selection_result, runtime_state)
333
333
  end
334
334
  end
335
335
 
336
- def evaluate_selection_with_resolved_keyword_args(kwarg_arguments, resolved_arguments, field_defn, ast_node, field_ast_nodes, object, is_eager_field, result_name, selection_result, parent_object, return_type, return_type_non_null, runtime_state) # rubocop:disable Metrics/ParameterLists
336
+ def evaluate_selection_with_resolved_keyword_args(kwarg_arguments, resolved_arguments, field_defn, ast_node, field_ast_nodes, object, result_name, selection_result, runtime_state) # rubocop:disable Metrics/ParameterLists
337
337
  runtime_state.current_field = field_defn
338
338
  runtime_state.current_arguments = resolved_arguments
339
339
  runtime_state.current_result_name = result_name
@@ -376,7 +376,8 @@ module GraphQL
376
376
  end
377
377
  after_lazy(app_result, field: field_defn, ast_node: ast_node, owner_object: object, arguments: resolved_arguments, result_name: result_name, result: selection_result, runtime_state: runtime_state) do |inner_result, runtime_state|
378
378
  owner_type = selection_result.graphql_result_type
379
- continue_value = continue_value(inner_result, field_defn, return_type_non_null, ast_node, result_name, selection_result)
379
+ return_type = field_defn.type
380
+ continue_value = continue_value(inner_result, field_defn, return_type.non_null?, ast_node, result_name, selection_result)
380
381
  if HALT != continue_value
381
382
  was_scoped = runtime_state.was_authorized_by_scope_items
382
383
  runtime_state.was_authorized_by_scope_items = nil
@@ -387,7 +388,7 @@ module GraphQL
387
388
  # If this field is a root mutation field, immediately resolve
388
389
  # all of its child fields before moving on to the next root mutation field.
389
390
  # (Subselections of this mutation will still be resolved level-by-level.)
390
- if is_eager_field
391
+ if selection_result.graphql_is_eager
391
392
  Interpreter::Resolve.resolve_all([field_result], @dataloader)
392
393
  end
393
394
  end
@@ -599,21 +600,11 @@ module GraphQL
599
600
  after_lazy(object_proxy, ast_node: ast_node, field: field, owner_object: owner_object, arguments: arguments, trace: false, result_name: result_name, result: selection_result, runtime_state: runtime_state) do |inner_object, runtime_state|
600
601
  continue_value = continue_value(inner_object, field, is_non_null, ast_node, result_name, selection_result)
601
602
  if HALT != continue_value
602
- response_hash = GraphQLResultHash.new(result_name, current_type, continue_value, selection_result, is_non_null)
603
+ response_hash = GraphQLResultHash.new(result_name, current_type, continue_value, selection_result, is_non_null, next_selections, false)
603
604
  set_result(selection_result, result_name, response_hash, true, is_non_null)
604
-
605
- gathered_selections = gather_selections(continue_value, current_type, next_selections)
606
- # There are two possibilities for `gathered_selections`:
607
- # 1. All selections of this object should be evaluated together (there are no runtime directives modifying execution).
608
- # This case is handled below, and the result can be written right into the main `response_hash` above.
609
- # In this case, `gathered_selections` is a hash of selections.
610
- # 2. Some selections of this object have runtime directives that may or may not modify execution.
611
- # That part of the selection is evaluated in an isolated way, writing into a sub-response object which is
612
- # eventually merged into the final response. In this case, `gathered_selections` is an array of things to run in isolation.
613
- # (Technically, it's possible that one of those entries _doesn't_ require isolation.)
614
- tap_or_each(gathered_selections) do |selections, is_selection_array|
605
+ each_gathered_selections(response_hash) do |selections, is_selection_array|
615
606
  if is_selection_array
616
- this_result = GraphQLResultHash.new(result_name, current_type, continue_value, selection_result, is_non_null)
607
+ this_result = GraphQLResultHash.new(result_name, current_type, continue_value, selection_result, is_non_null, selections, false)
617
608
  final_result = response_hash
618
609
  else
619
610
  this_result = response_hash
@@ -621,11 +612,9 @@ module GraphQL
621
612
  end
622
613
 
623
614
  evaluate_selections(
624
- false,
625
615
  selections,
626
616
  this_result,
627
617
  final_result,
628
- owner_object.object,
629
618
  runtime_state,
630
619
  )
631
620
  end
@@ -636,7 +625,7 @@ module GraphQL
636
625
  # This is true for objects, unions, and interfaces
637
626
  use_dataloader_job = !inner_type.unwrap.kind.input?
638
627
  inner_type_non_null = inner_type.non_null?
639
- response_list = GraphQLResultArray.new(result_name, current_type, response_list, selection_result, is_non_null)
628
+ response_list = GraphQLResultArray.new(result_name, current_type, owner_object, selection_result, is_non_null, next_selections, false)
640
629
  set_result(selection_result, result_name, response_list, true, is_non_null)
641
630
  idx = nil
642
631
  list_value = begin
@@ -646,10 +635,10 @@ module GraphQL
646
635
  idx += 1
647
636
  if use_dataloader_job
648
637
  @dataloader.append_job do
649
- resolve_list_item(inner_value, inner_type, inner_type_non_null, ast_node, field, owner_object, arguments, this_idx, response_list, next_selections, owner_type, was_scoped, runtime_state)
638
+ resolve_list_item(inner_value, inner_type, inner_type_non_null, ast_node, field, owner_object, arguments, this_idx, response_list, owner_type, was_scoped, runtime_state)
650
639
  end
651
640
  else
652
- resolve_list_item(inner_value, inner_type, inner_type_non_null, ast_node, field, owner_object, arguments, this_idx, response_list, next_selections, owner_type, was_scoped, runtime_state)
641
+ resolve_list_item(inner_value, inner_type, inner_type_non_null, ast_node, field, owner_object, arguments, this_idx, response_list, owner_type, was_scoped, runtime_state)
653
642
  end
654
643
  end
655
644
 
@@ -680,7 +669,7 @@ module GraphQL
680
669
  end
681
670
  end
682
671
 
683
- def resolve_list_item(inner_value, inner_type, inner_type_non_null, ast_node, field, owner_object, arguments, this_idx, response_list, next_selections, owner_type, was_scoped, runtime_state) # rubocop:disable Metrics/ParameterLists
672
+ def resolve_list_item(inner_value, inner_type, inner_type_non_null, ast_node, field, owner_object, arguments, this_idx, response_list, owner_type, was_scoped, runtime_state) # rubocop:disable Metrics/ParameterLists
684
673
  runtime_state.current_result_name = this_idx
685
674
  runtime_state.current_result = response_list
686
675
  call_method_on_directives(:resolve_each, owner_object, ast_node.directives) do
@@ -688,7 +677,7 @@ module GraphQL
688
677
  after_lazy(inner_value, ast_node: ast_node, field: field, owner_object: owner_object, arguments: arguments, result_name: this_idx, result: response_list, runtime_state: runtime_state) do |inner_inner_value, runtime_state|
689
678
  continue_value = continue_value(inner_inner_value, field, inner_type_non_null, ast_node, this_idx, response_list)
690
679
  if HALT != continue_value
691
- continue_field(continue_value, owner_type, field, inner_type, ast_node, next_selections, false, owner_object, arguments, this_idx, response_list, was_scoped, runtime_state)
680
+ continue_field(continue_value, owner_type, field, inner_type, ast_node, response_list.graphql_selections, false, owner_object, arguments, this_idx, response_list, was_scoped, runtime_state)
692
681
  end
693
682
  end
694
683
  end
@@ -20,7 +20,7 @@ module GraphQL
20
20
  # @param queries [Array<GraphQL::Query, Hash>]
21
21
  # @param context [Hash]
22
22
  # @param max_complexity [Integer, nil]
23
- # @return [Array<Hash>] One result per query
23
+ # @return [Array<GraphQL::Query::Result>] One result per query
24
24
  def run_all(schema, query_options, context: {}, max_complexity: schema.max_complexity)
25
25
  queries = query_options.map do |opts|
26
26
  case opts
@@ -20,6 +20,15 @@ module GraphQL
20
20
  @definition_line = definition_line
21
21
  super(**_rest)
22
22
  end
23
+
24
+ def marshal_dump
25
+ super << @definition_line
26
+ end
27
+
28
+ def marshal_load(values)
29
+ @definition_line = values.pop
30
+ super
31
+ end
23
32
  end
24
33
 
25
34
  attr_reader :filename
@@ -265,6 +274,8 @@ module GraphQL
265
274
  ]
266
275
 
267
276
  def generate_initialize
277
+ return if method_defined?(:marshal_load, false) # checking for `:initialize` doesn't work right
278
+
268
279
  scalar_method_names = @scalar_methods
269
280
  # TODO: These probably should be scalar methods, but `types` returns an array
270
281
  [:types, :description].each do |extra_method|
@@ -273,18 +284,20 @@ module GraphQL
273
284
  end
274
285
  end
275
286
 
276
- all_method_names = scalar_method_names + @children_methods.keys
287
+ children_method_names = @children_methods.keys
288
+
289
+ all_method_names = scalar_method_names + children_method_names
277
290
  if all_method_names.include?(:alias)
278
291
  # Rather than complicating this special case,
279
292
  # let it be overridden (in field)
280
293
  return
281
294
  else
282
295
  arguments = scalar_method_names.map { |m| "#{m}: nil"} +
283
- @children_methods.keys.map { |m| "#{m}: NO_CHILDREN" } +
296
+ children_method_names.map { |m| "#{m}: NO_CHILDREN" } +
284
297
  DEFAULT_INITIALIZE_OPTIONS
285
298
 
286
299
  assignments = scalar_method_names.map { |m| "@#{m} = #{m}"} +
287
- @children_methods.keys.map { |m| "@#{m} = #{m}.freeze" }
300
+ children_method_names.map { |m| "@#{m} = #{m}.freeze" }
288
301
 
289
302
  if name.end_with?("Definition") && name != "FragmentDefinition"
290
303
  arguments << "definition_pos: nil"
@@ -292,7 +305,7 @@ module GraphQL
292
305
  end
293
306
 
294
307
  keywords = scalar_method_names.map { |m| "#{m}: #{m}"} +
295
- @children_methods.keys.map { |m| "#{m}: #{m}" }
308
+ children_method_names.map { |m| "#{m}: #{m}" }
296
309
 
297
310
  module_eval <<-RUBY, __FILE__, __LINE__
298
311
  def initialize(#{arguments.join(", ")})
@@ -304,9 +317,21 @@ module GraphQL
304
317
  #{assignments.join("\n")}
305
318
  end
306
319
 
307
- def self.from_a(filename, line, col, #{(scalar_method_names + @children_methods.keys).join(", ")})
320
+ def self.from_a(filename, line, col, #{all_method_names.join(", ")})
308
321
  self.new(filename: filename, line: line, col: col, #{keywords.join(", ")})
309
322
  end
323
+
324
+ def marshal_dump
325
+ [
326
+ line, col, # use methods here to force them to be calculated
327
+ @filename,
328
+ #{all_method_names.map { |n| "@#{n}," }.join}
329
+ ]
330
+ end
331
+
332
+ def marshal_load(values)
333
+ @line, @col, @filename #{all_method_names.map { |n| ", @#{n}"}.join} = values
334
+ end
310
335
  RUBY
311
336
  end
312
337
  end
@@ -369,16 +394,6 @@ module GraphQL
369
394
 
370
395
  # A single selection in a GraphQL query.
371
396
  class Field < AbstractNode
372
- scalar_methods :name, :alias
373
- children_methods({
374
- arguments: GraphQL::Language::Nodes::Argument,
375
- selections: GraphQL::Language::Nodes::Field,
376
- directives: GraphQL::Language::Nodes::Directive,
377
- })
378
-
379
- # @!attribute selections
380
- # @return [Array<Nodes::Field>] Selections on this object (or empty array if this is a scalar field)
381
-
382
397
  def initialize(name: nil, arguments: NONE, directives: NONE, selections: NONE, field_alias: nil, line: nil, col: nil, pos: nil, filename: nil, source: nil)
383
398
  @name = name
384
399
  @arguments = arguments || NONE
@@ -397,24 +412,27 @@ module GraphQL
397
412
  self.new(filename: filename, line: line, col: col, field_alias: field_alias, name: name, arguments: arguments, directives: directives, selections: selections)
398
413
  end
399
414
 
400
- # Override this because default is `:fields`
401
- self.children_method_name = :selections
402
- end
415
+ def marshal_dump
416
+ [line, col, @filename, @name, @arguments, @directives, @selections, @alias]
417
+ end
403
418
 
404
- # A reusable fragment, defined at document-level.
405
- class FragmentDefinition < AbstractNode
406
- scalar_methods :name, :type
419
+ def marshal_load(values)
420
+ @line, @col, @filename, @name, @arguments, @directives, @selections, @alias = values
421
+ end
422
+
423
+ scalar_methods :name, :alias
407
424
  children_methods({
425
+ arguments: GraphQL::Language::Nodes::Argument,
408
426
  selections: GraphQL::Language::Nodes::Field,
409
427
  directives: GraphQL::Language::Nodes::Directive,
410
428
  })
411
429
 
412
- self.children_method_name = :definitions
413
- # @!attribute name
414
- # @return [String] the identifier for this fragment, which may be applied with `...#{name}`
430
+ # Override this because default is `:fields`
431
+ self.children_method_name = :selections
432
+ end
415
433
 
416
- # @!attribute type
417
- # @return [String] the type condition for this fragment (name of type which it may apply to)
434
+ # A reusable fragment, defined at document-level.
435
+ class FragmentDefinition < AbstractNode
418
436
  def initialize(name: nil, type: nil, directives: NONE, selections: NONE, filename: nil, pos: nil, source: nil, line: nil, col: nil)
419
437
  @name = name
420
438
  @type = type
@@ -430,6 +448,22 @@ module GraphQL
430
448
  def self.from_a(filename, line, col, name, type, directives, selections)
431
449
  self.new(filename: filename, line: line, col: col, name: name, type: type, directives: directives, selections: selections)
432
450
  end
451
+
452
+ def marshal_dump
453
+ [line, col, @filename, @name, @type, @directives, @selections]
454
+ end
455
+
456
+ def marshal_load(values)
457
+ @line, @col, @filename, @name, @type, @directives, @selections = values
458
+ end
459
+
460
+ scalar_methods :name, :type
461
+ children_methods({
462
+ selections: GraphQL::Language::Nodes::Field,
463
+ directives: GraphQL::Language::Nodes::Directive,
464
+ })
465
+
466
+ self.children_method_name = :definitions
433
467
  end
434
468
 
435
469
  # Application of a named fragment in a selection