graphql 2.3.2 → 2.3.4

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 573ce6f5423ca2d9eb0ca3dab40f01869501f834c3b48d5cac7f7c06fbf36da9
4
- data.tar.gz: c3b1f0393d2838a2478a36a43cec88560832c220a3896f2ee4c715d013d1758c
3
+ metadata.gz: c8f2d38dd0c349521f7f22050bb70cee1f06a7832de74d5afe523a35310ed318
4
+ data.tar.gz: da047a5e11a1441060411c47468daad16300db1dc7064ab1b1a76d2e519e76fd
5
5
  SHA512:
6
- metadata.gz: 14d6c96c20c8fdb56ecddf0279e24e83c862d4133c72b3cebc44dca9e40e1c684b4f4a4c45fca81451d48d1bb97a4e6c3ae13499a40e12a76926e679a12a13f2
7
- data.tar.gz: 44157aaa761da8c9f82afa9e31533ee3c87cdf4257256ec84f70f0e30dff8dc1830486c2ff02b4464a67e8815518466451ae598eabc12249cf2edaad6a9371f1
6
+ metadata.gz: 73bd380530a4183241587083beb2ef6c96709657fb18e702a294a37c22f26e2141b2111b96c79570b9588d330e9c8d851fd532cdaf6d6fbd55f9dd5b30c6fe4e
7
+ data.tar.gz: 917e88d0cec3cbc760ec89714cf31325088f94f0a93094b3fcbf1cc3c07f52a99e30f0e418e561518c0a7deef0358dfa0ae457b8bad88fb50883aacb9d7dae7f
@@ -8,6 +8,7 @@ module GraphQL
8
8
  # - `complexities_on_type` holds complexity scores for each type
9
9
  def initialize(query)
10
10
  super
11
+ @skip_introspection_fields = !query.schema.max_complexity_count_introspection_fields
11
12
  @complexities_on_type_by_query = {}
12
13
  end
13
14
 
@@ -51,6 +52,7 @@ module GraphQL
51
52
  # we'll visit them when we hit the spreads instead
52
53
  return if visitor.visiting_fragment_definition?
53
54
  return if visitor.skipping?
55
+ return if @skip_introspection_fields && visitor.field_definition.introspection?
54
56
  parent_type = visitor.parent_type_definition
55
57
  field_key = node.alias || node.name
56
58
 
@@ -68,6 +70,7 @@ module GraphQL
68
70
  # we'll visit them when we hit the spreads instead
69
71
  return if visitor.visiting_fragment_definition?
70
72
  return if visitor.skipping?
73
+ return if @skip_introspection_fields && visitor.field_definition.introspection?
71
74
  scopes_stack = @complexities_on_type_by_query[visitor.query]
72
75
  scopes_stack.pop
73
76
  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
@@ -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,8 +5,10 @@ module GraphQL
5
5
  class Interpreter
6
6
  class Runtime
7
7
  module GraphQLResult
8
- def initialize(result_name, parent_result, is_non_null_in_parent)
8
+ def initialize(result_name, result_type, application_value, parent_result, is_non_null_in_parent)
9
9
  @graphql_parent = parent_result
10
+ @graphql_application_value = application_value
11
+ @graphql_result_type = result_type
10
12
  if parent_result && parent_result.graphql_dead
11
13
  @graphql_dead = true
12
14
  end
@@ -26,14 +28,14 @@ module GraphQL
26
28
  end
27
29
 
28
30
  attr_accessor :graphql_dead
29
- attr_reader :graphql_parent, :graphql_result_name, :graphql_is_non_null_in_parent
31
+ attr_reader :graphql_parent, :graphql_result_name, :graphql_is_non_null_in_parent, :graphql_application_value, :graphql_result_type
30
32
 
31
33
  # @return [Hash] Plain-Ruby result data (`@graphql_metadata` contains Result wrapper objects)
32
34
  attr_accessor :graphql_result_data
33
35
  end
34
36
 
35
37
  class GraphQLResultHash
36
- def initialize(_result_name, _parent_result, _is_non_null_in_parent)
38
+ def initialize(_result_name, _result_type, _application_value, _parent_result, _is_non_null_in_parent)
37
39
  super
38
40
  @graphql_result_data = {}
39
41
  end
@@ -121,7 +123,7 @@ module GraphQL
121
123
  class GraphQLResultArray
122
124
  include GraphQLResult
123
125
 
124
- def initialize(_result_name, _parent_result, _is_non_null_in_parent)
126
+ def initialize(_result_name, _result_type, _application_value, _parent_result, _is_non_null_in_parent)
125
127
  super
126
128
  @graphql_result_data = []
127
129
  end
@@ -11,7 +11,6 @@ module GraphQL
11
11
  class Runtime
12
12
  class CurrentState
13
13
  def initialize
14
- @current_object = nil
15
14
  @current_field = nil
16
15
  @current_arguments = nil
17
16
  @current_result_name = nil
@@ -19,8 +18,12 @@ module GraphQL
19
18
  @was_authorized_by_scope_items = nil
20
19
  end
21
20
 
21
+ def current_object
22
+ @current_result.graphql_application_value
23
+ end
24
+
22
25
  attr_accessor :current_result, :current_result_name,
23
- :current_arguments, :current_field, :current_object, :was_authorized_by_scope_items
26
+ :current_arguments, :current_field, :was_authorized_by_scope_items
24
27
  end
25
28
 
26
29
  # @return [GraphQL::Query]
@@ -39,7 +42,7 @@ module GraphQL
39
42
  @lazies_at_depth = lazies_at_depth
40
43
  @schema = query.schema
41
44
  @context = query.context
42
- @response = GraphQLResultHash.new(nil, nil, false)
45
+ @response = nil
43
46
  # Identify runtime directives by checking which of this schema's directives have overridden `def self.resolve`
44
47
  @runtime_directive_names = []
45
48
  noop_resolve_owner = GraphQL::Schema::Directive.singleton_class
@@ -79,12 +82,11 @@ module GraphQL
79
82
  root_operation = query.selected_operation
80
83
  root_op_type = root_operation.operation_type || "query"
81
84
  root_type = schema.root_type_for_operation(root_op_type)
82
-
83
- st = get_current_runtime_state
84
- st.current_object = query.root_value
85
- st.current_result = @response
86
85
  runtime_object = root_type.wrap(query.root_value, context)
87
86
  runtime_object = schema.sync_lazy(runtime_object)
87
+ @response = GraphQLResultHash.new(nil, root_type, runtime_object, nil, false)
88
+ st = get_current_runtime_state
89
+ st.current_result = @response
88
90
 
89
91
  if runtime_object.nil?
90
92
  # Root .authorized? returned false.
@@ -101,7 +103,7 @@ module GraphQL
101
103
  # directly evaluated and the results can be written right into the main response hash.
102
104
  tap_or_each(gathered_selections) do |selections, is_selection_array|
103
105
  if is_selection_array
104
- selection_response = GraphQLResultHash.new(nil, nil, false)
106
+ selection_response = GraphQLResultHash.new(nil, root_type, runtime_object, nil, false)
105
107
  final_response = @response
106
108
  else
107
109
  selection_response = @response
@@ -109,26 +111,14 @@ module GraphQL
109
111
  end
110
112
 
111
113
  @dataloader.append_job {
112
- st = get_current_runtime_state
113
- st.current_object = query.root_value
114
- st.current_result_name = nil
115
- st.current_result = selection_response
116
- # This is a less-frequent case; use a fast check since it's often not there.
117
- if (directives = selections[:graphql_directives])
118
- selections.delete(:graphql_directives)
119
- end
120
- call_method_on_directives(:resolve, runtime_object, directives) do
121
- evaluate_selections(
122
- runtime_object,
123
- root_type,
124
- root_op_type == "mutation",
125
- selections,
126
- selection_response,
127
- final_response,
128
- nil,
129
- st,
130
- )
131
- end
114
+ evaluate_selections(
115
+ root_op_type == "mutation",
116
+ selections,
117
+ selection_response,
118
+ final_response,
119
+ nil,
120
+ nil,
121
+ )
132
122
  }
133
123
  end
134
124
  end
@@ -137,7 +127,6 @@ module GraphQL
137
127
  end
138
128
 
139
129
  def gather_selections(owner_object, owner_type, selections, selections_to_run = nil, selections_by_name = {})
140
-
141
130
  selections.each do |node|
142
131
  # Skip gathering this if the directive says so
143
132
  if !directives_include?(node, owner_object, owner_type)
@@ -182,17 +171,26 @@ module GraphQL
182
171
  type_defn = schema.get_type(node.type.name, context)
183
172
 
184
173
  if query.warden.possible_types(type_defn).include?(owner_type)
185
- gather_selections(owner_object, owner_type, node.selections, selections_to_run, next_selections)
174
+ result = gather_selections(owner_object, owner_type, node.selections, selections_to_run, next_selections)
175
+ if !result.equal?(next_selections)
176
+ selections_to_run = result
177
+ end
186
178
  end
187
179
  else
188
180
  # it's an untyped fragment, definitely continue
189
- gather_selections(owner_object, owner_type, node.selections, selections_to_run, next_selections)
181
+ result = gather_selections(owner_object, owner_type, node.selections, selections_to_run, next_selections)
182
+ if !result.equal?(next_selections)
183
+ selections_to_run = result
184
+ end
190
185
  end
191
186
  when GraphQL::Language::Nodes::FragmentSpread
192
187
  fragment_def = query.fragments[node.name]
193
188
  type_defn = query.get_type(fragment_def.type.name)
194
189
  if query.warden.possible_types(type_defn).include?(owner_type)
195
- gather_selections(owner_object, owner_type, fragment_def.selections, selections_to_run, next_selections)
190
+ result = gather_selections(owner_object, owner_type, fragment_def.selections, selections_to_run, next_selections)
191
+ if !result.equal?(next_selections)
192
+ selections_to_run = result
193
+ end
196
194
  end
197
195
  else
198
196
  raise "Invariant: unexpected selection class: #{node.class}"
@@ -205,36 +203,44 @@ module GraphQL
205
203
  NO_ARGS = GraphQL::EmptyObjects::EMPTY_HASH
206
204
 
207
205
  # @return [void]
208
- def evaluate_selections(owner_object, owner_type, is_eager_selection, gathered_selections, selections_result, target_result, parent_object, runtime_state) # rubocop:disable Metrics/ParameterLists
209
- finished_jobs = 0
210
- enqueued_jobs = gathered_selections.size
211
- gathered_selections.each do |result_name, field_ast_nodes_or_ast_node|
212
- @dataloader.append_job {
213
- runtime_state = get_current_runtime_state
214
- evaluate_selection(
215
- result_name, field_ast_nodes_or_ast_node, owner_object, owner_type, is_eager_selection, selections_result, parent_object, runtime_state
216
- )
217
- finished_jobs += 1
218
- if target_result && finished_jobs == enqueued_jobs
219
- selections_result.merge_into(target_result)
206
+ def evaluate_selections(is_eager_selection, gathered_selections, selections_result, target_result, parent_object, runtime_state) # rubocop:disable Metrics/ParameterLists
207
+ runtime_state ||= get_current_runtime_state
208
+ runtime_state.current_result_name = nil
209
+ runtime_state.current_result = selections_result
210
+ # This is a less-frequent case; use a fast check since it's often not there.
211
+ if (directives = gathered_selections[:graphql_directives])
212
+ gathered_selections.delete(:graphql_directives)
213
+ end
214
+
215
+ call_method_on_directives(:resolve, selections_result.graphql_application_value, directives) do
216
+ finished_jobs = 0
217
+ enqueued_jobs = gathered_selections.size
218
+ gathered_selections.each do |result_name, field_ast_nodes_or_ast_node|
219
+ @dataloader.append_job {
220
+ evaluate_selection(
221
+ result_name, field_ast_nodes_or_ast_node, is_eager_selection, selections_result, parent_object
222
+ )
223
+ finished_jobs += 1
224
+ if target_result && finished_jobs == enqueued_jobs
225
+ selections_result.merge_into(target_result)
226
+ end
227
+ }
228
+ # Field resolution may pause the fiber,
229
+ # so it wouldn't get to the `Resolve` call that happens below.
230
+ # So instead trigger a run from this outer context.
231
+ if is_eager_selection
232
+ @dataloader.clear_cache
233
+ @dataloader.run
234
+ @dataloader.clear_cache
220
235
  end
221
- }
222
- # Field resolution may pause the fiber,
223
- # so it wouldn't get to the `Resolve` call that happens below.
224
- # So instead trigger a run from this outer context.
225
- if is_eager_selection
226
- @dataloader.clear_cache
227
- @dataloader.run
228
- @dataloader.clear_cache
229
236
  end
237
+ selections_result
230
238
  end
231
-
232
- selections_result
233
239
  end
234
240
 
235
241
  # @return [void]
236
- def evaluate_selection(result_name, field_ast_nodes_or_ast_node, owner_object, owner_type, is_eager_field, selections_result, parent_object, runtime_state) # rubocop:disable Metrics/ParameterLists
237
- return if dead_result?(selections_result)
242
+ def evaluate_selection(result_name, field_ast_nodes_or_ast_node, is_eager_field, selections_result, parent_object) # rubocop:disable Metrics/ParameterLists
243
+ return if selections_result.graphql_dead
238
244
  # As a performance optimization, the hash key will be a `Node` if
239
245
  # there's only one selection of the field. But if there are multiple
240
246
  # selections of the field, it will be an Array of nodes
@@ -246,13 +252,16 @@ module GraphQL
246
252
  ast_node = field_ast_nodes_or_ast_node
247
253
  end
248
254
  field_name = ast_node.name
255
+ owner_type = selections_result.graphql_result_type
249
256
  field_defn = query.warden.get_field(owner_type, field_name)
250
257
 
251
258
  # Set this before calling `run_with_directives`, so that the directive can have the latest path
259
+ runtime_state = get_current_runtime_state
252
260
  runtime_state.current_field = field_defn
253
261
  runtime_state.current_result = selections_result
254
262
  runtime_state.current_result_name = result_name
255
263
 
264
+ owner_object = selections_result.graphql_application_value
256
265
  if field_defn.dynamic_introspection
257
266
  owner_object = field_defn.owner.wrap(owner_object, context)
258
267
  end
@@ -262,24 +271,24 @@ module GraphQL
262
271
  resolved_arguments = GraphQL::Execution::Interpreter::Arguments::EMPTY
263
272
  if field_defn.extras.size == 0
264
273
  evaluate_selection_with_resolved_keyword_args(
265
- NO_ARGS, resolved_arguments, field_defn, ast_node, field_ast_nodes, owner_type, owner_object, is_eager_field, result_name, selections_result, parent_object, return_type, return_type.non_null?, runtime_state
274
+ 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
266
275
  )
267
276
  else
268
- evaluate_selection_with_args(resolved_arguments, field_defn, ast_node, field_ast_nodes, owner_type, owner_object, is_eager_field, result_name, selections_result, parent_object, return_type, runtime_state)
277
+ 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)
269
278
  end
270
279
  else
271
280
  @query.arguments_cache.dataload_for(ast_node, field_defn, owner_object) do |resolved_arguments|
272
281
  runtime_state = get_current_runtime_state # This might be in a different fiber
273
- evaluate_selection_with_args(resolved_arguments, field_defn, ast_node, field_ast_nodes, owner_type, owner_object, is_eager_field, result_name, selections_result, parent_object, return_type, runtime_state)
282
+ 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)
274
283
  end
275
284
  end
276
285
  end
277
286
 
278
- def evaluate_selection_with_args(arguments, field_defn, ast_node, field_ast_nodes, owner_type, object, is_eager_field, result_name, selection_result, parent_object, return_type, runtime_state) # rubocop:disable Metrics/ParameterLists
287
+ 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
279
288
  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|
280
289
  return_type_non_null = return_type.non_null?
281
290
  if resolved_arguments.is_a?(GraphQL::ExecutionError) || resolved_arguments.is_a?(GraphQL::UnauthorizedError)
282
- continue_value(resolved_arguments, owner_type, field_defn, return_type_non_null, ast_node, result_name, selection_result)
291
+ continue_value(resolved_arguments, field_defn, return_type_non_null, ast_node, result_name, selection_result)
283
292
  next
284
293
  end
285
294
 
@@ -328,13 +337,12 @@ module GraphQL
328
337
  resolved_arguments.keyword_arguments
329
338
  end
330
339
 
331
- evaluate_selection_with_resolved_keyword_args(kwarg_arguments, resolved_arguments, field_defn, ast_node, field_ast_nodes, owner_type, object, is_eager_field, result_name, selection_result, parent_object, return_type, return_type_non_null, runtime_state)
340
+ 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
341
  end
333
342
  end
334
343
 
335
- def evaluate_selection_with_resolved_keyword_args(kwarg_arguments, resolved_arguments, field_defn, ast_node, field_ast_nodes, owner_type, object, is_eager_field, result_name, selection_result, parent_object, return_type, return_type_non_null, runtime_state) # rubocop:disable Metrics/ParameterLists
344
+ 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
345
  runtime_state.current_field = field_defn
337
- runtime_state.current_object = object
338
346
  runtime_state.current_arguments = resolved_arguments
339
347
  runtime_state.current_result_name = result_name
340
348
  runtime_state.current_result = selection_result
@@ -356,7 +364,6 @@ module GraphQL
356
364
  # This might be executed in a different context; reset this info
357
365
  runtime_state = get_current_runtime_state
358
366
  runtime_state.current_field = field_defn
359
- runtime_state.current_object = object
360
367
  runtime_state.current_arguments = resolved_arguments
361
368
  runtime_state.current_result_name = result_name
362
369
  runtime_state.current_result = selection_result
@@ -376,7 +383,8 @@ module GraphQL
376
383
  end
377
384
  end
378
385
  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|
379
- continue_value = continue_value(inner_result, owner_type, field_defn, return_type_non_null, ast_node, result_name, selection_result)
386
+ owner_type = selection_result.graphql_result_type
387
+ continue_value = continue_value(inner_result, field_defn, return_type_non_null, ast_node, result_name, selection_result)
380
388
  if HALT != continue_value
381
389
  was_scoped = runtime_state.was_authorized_by_scope_items
382
390
  runtime_state.was_authorized_by_scope_items = nil
@@ -384,25 +392,16 @@ module GraphQL
384
392
  end
385
393
  end
386
394
  end
387
-
388
395
  # If this field is a root mutation field, immediately resolve
389
396
  # all of its child fields before moving on to the next root mutation field.
390
397
  # (Subselections of this mutation will still be resolved level-by-level.)
391
398
  if is_eager_field
392
399
  Interpreter::Resolve.resolve_all([field_result], @dataloader)
393
- else
394
- # Return this from `after_lazy` because it might be another lazy that needs to be resolved
395
- field_result
396
400
  end
397
401
  end
398
402
 
399
-
400
- def dead_result?(selection_result)
401
- selection_result.graphql_dead # || ((parent = selection_result.graphql_parent) && parent.graphql_dead)
402
- end
403
-
404
403
  def set_result(selection_result, result_name, value, is_child_result, is_non_null)
405
- if !dead_result?(selection_result)
404
+ if !selection_result.graphql_dead
406
405
  if value.nil? && is_non_null
407
406
  # This is an invalid nil that should be propagated
408
407
  # One caller of this method passes a block,
@@ -456,11 +455,13 @@ module GraphQL
456
455
  end
457
456
 
458
457
  HALT = Object.new
459
- def continue_value(value, parent_type, field, is_non_null, ast_node, result_name, selection_result) # rubocop:disable Metrics/ParameterLists
458
+ def continue_value(value, field, is_non_null, ast_node, result_name, selection_result) # rubocop:disable Metrics/ParameterLists
460
459
  case value
461
460
  when nil
462
461
  if is_non_null
463
462
  set_result(selection_result, result_name, nil, false, is_non_null) do
463
+ # When this comes from a list item, use the parent object:
464
+ parent_type = selection_result.is_a?(GraphQLResultArray) ? selection_result.graphql_parent.graphql_result_type : selection_result.graphql_result_type
464
465
  # This block is called if `result_name` is not dead. (Maybe a previous invalid nil caused it be marked dead.)
465
466
  err = parent_type::InvalidNullError.new(parent_type, field, value)
466
467
  schema.type_error(err, context)
@@ -474,7 +475,7 @@ module GraphQL
474
475
  # to avoid the overhead of checking three different classes
475
476
  # every time.
476
477
  if value.is_a?(GraphQL::ExecutionError)
477
- if selection_result.nil? || !dead_result?(selection_result)
478
+ if selection_result.nil? || !selection_result.graphql_dead
478
479
  value.path ||= current_path
479
480
  value.ast_node ||= ast_node
480
481
  context.errors << value
@@ -492,7 +493,7 @@ module GraphQL
492
493
  rescue GraphQL::ExecutionError => err
493
494
  err
494
495
  end
495
- continue_value(next_value, parent_type, field, is_non_null, ast_node, result_name, selection_result)
496
+ continue_value(next_value, field, is_non_null, ast_node, result_name, selection_result)
496
497
  elsif value.is_a?(GraphQL::UnauthorizedError)
497
498
  # this hook might raise & crash, or it might return
498
499
  # a replacement value
@@ -501,7 +502,7 @@ module GraphQL
501
502
  rescue GraphQL::ExecutionError => err
502
503
  err
503
504
  end
504
- continue_value(next_value, parent_type, field, is_non_null, ast_node, result_name, selection_result)
505
+ continue_value(next_value, field, is_non_null, ast_node, result_name, selection_result)
505
506
  elsif GraphQL::Execution::SKIP == value
506
507
  # It's possible a lazy was already written here
507
508
  case selection_result
@@ -524,7 +525,7 @@ module GraphQL
524
525
  # It's an array full of execution errors; add them all.
525
526
  if value.any? && value.all?(GraphQL::ExecutionError)
526
527
  list_type_at_all = (field && (field.type.list?))
527
- if selection_result.nil? || !dead_result?(selection_result)
528
+ if selection_result.nil? || !selection_result.graphql_dead
528
529
  value.each_with_index do |error, index|
529
530
  error.ast_node ||= ast_node
530
531
  error.path ||= current_path + (list_type_at_all ? [index] : [])
@@ -604,9 +605,9 @@ module GraphQL
604
605
  err
605
606
  end
606
607
  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|
607
- continue_value = continue_value(inner_object, owner_type, field, is_non_null, ast_node, result_name, selection_result)
608
+ continue_value = continue_value(inner_object, field, is_non_null, ast_node, result_name, selection_result)
608
609
  if HALT != continue_value
609
- response_hash = GraphQLResultHash.new(result_name, selection_result, is_non_null)
610
+ response_hash = GraphQLResultHash.new(result_name, current_type, continue_value, selection_result, is_non_null)
610
611
  set_result(selection_result, result_name, response_hash, true, is_non_null)
611
612
 
612
613
  gathered_selections = gather_selections(continue_value, current_type, next_selections)
@@ -620,34 +621,21 @@ module GraphQL
620
621
  # (Technically, it's possible that one of those entries _doesn't_ require isolation.)
621
622
  tap_or_each(gathered_selections) do |selections, is_selection_array|
622
623
  if is_selection_array
623
- this_result = GraphQLResultHash.new(result_name, selection_result, is_non_null)
624
+ this_result = GraphQLResultHash.new(result_name, current_type, continue_value, selection_result, is_non_null)
624
625
  final_result = response_hash
625
626
  else
626
627
  this_result = response_hash
627
628
  final_result = nil
628
629
  end
629
- # reset this mutable state
630
- # Unset `result_name` here because it's already included in the new response hash
631
- runtime_state.current_object = continue_value
632
- runtime_state.current_result_name = nil
633
- runtime_state.current_result = this_result
634
- # This is a less-frequent case; use a fast check since it's often not there.
635
- if (directives = selections[:graphql_directives])
636
- selections.delete(:graphql_directives)
637
- end
638
- call_method_on_directives(:resolve, continue_value, directives) do
639
- evaluate_selections(
640
- continue_value,
641
- current_type,
642
- false,
643
- selections,
644
- this_result,
645
- final_result,
646
- owner_object.object,
647
- runtime_state,
648
- )
649
- this_result
650
- end
630
+
631
+ evaluate_selections(
632
+ false,
633
+ selections,
634
+ this_result,
635
+ final_result,
636
+ owner_object.object,
637
+ runtime_state,
638
+ )
651
639
  end
652
640
  end
653
641
  end
@@ -656,7 +644,7 @@ module GraphQL
656
644
  # This is true for objects, unions, and interfaces
657
645
  use_dataloader_job = !inner_type.unwrap.kind.input?
658
646
  inner_type_non_null = inner_type.non_null?
659
- response_list = GraphQLResultArray.new(result_name, selection_result, is_non_null)
647
+ response_list = GraphQLResultArray.new(result_name, current_type, response_list, selection_result, is_non_null)
660
648
  set_result(selection_result, result_name, response_list, true, is_non_null)
661
649
  idx = nil
662
650
  list_value = begin
@@ -694,7 +682,7 @@ module GraphQL
694
682
  end
695
683
  # Detect whether this error came while calling `.each` (before `idx` is set) or while running list *items* (after `idx` is set)
696
684
  error_is_non_null = idx.nil? ? is_non_null : inner_type.non_null?
697
- continue_value(list_value, owner_type, field, error_is_non_null, ast_node, result_name, selection_result)
685
+ continue_value(list_value, field, error_is_non_null, ast_node, result_name, selection_result)
698
686
  else
699
687
  raise "Invariant: Unhandled type kind #{current_type.kind} (#{current_type})"
700
688
  end
@@ -706,7 +694,7 @@ module GraphQL
706
694
  call_method_on_directives(:resolve_each, owner_object, ast_node.directives) do
707
695
  # This will update `response_list` with the lazy
708
696
  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|
709
- continue_value = continue_value(inner_inner_value, owner_type, field, inner_type_non_null, ast_node, this_idx, response_list)
697
+ continue_value = continue_value(inner_inner_value, field, inner_type_non_null, ast_node, this_idx, response_list)
710
698
  if HALT != continue_value
711
699
  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)
712
700
  end
@@ -728,7 +716,6 @@ module GraphQL
728
716
  raw_dir_args = arguments(nil, dir_defn, dir_node)
729
717
  dir_args = continue_value(
730
718
  raw_dir_args, # value
731
- dir_defn, # parent_type
732
719
  nil, # field
733
720
  false, # is_non_null
734
721
  dir_node, # ast_node
@@ -794,7 +781,6 @@ module GraphQL
794
781
  # In that case, this will initialize a new state
795
782
  # to avoid conflicting with the parent fiber.
796
783
  runtime_state = get_current_runtime_state
797
- runtime_state.current_object = owner_object
798
784
  runtime_state.current_field = field
799
785
  runtime_state.current_arguments = arguments
800
786
  runtime_state.current_result_name = result_name
@@ -20,26 +20,29 @@ 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
26
35
 
27
36
  def line
28
- @line ||= (@source_string && @pos) ? @source_string[0..@pos].count("\n") + 1 : nil
37
+ @line ||= @source.line_at(@pos)
29
38
  end
30
39
 
31
40
  def col
32
- @col ||= if @source_string && @pos
33
- if @pos == 0
34
- 1
35
- else
36
- @source_string[0..@pos].split("\n").last.length
37
- end
38
- end
41
+ @col ||= @source.column_at(@pos)
39
42
  end
40
43
 
41
44
  def definition_line
42
- @definition_line ||= (@source_string && @definition_pos) ? @source_string[0..@definition_pos].count("\n") + 1 : nil
45
+ @definition_line ||= (@source && @definition_pos) ? @source.line_at(@definition_pos) : nil
43
46
  end
44
47
 
45
48
  # Value equality
@@ -267,7 +270,7 @@ module GraphQL
267
270
  "col: nil",
268
271
  "pos: nil",
269
272
  "filename: nil",
270
- "source_string: nil",
273
+ "source: nil",
271
274
  ]
272
275
 
273
276
  def generate_initialize
@@ -279,18 +282,20 @@ module GraphQL
279
282
  end
280
283
  end
281
284
 
282
- all_method_names = scalar_method_names + @children_methods.keys
285
+ children_method_names = @children_methods.keys
286
+
287
+ all_method_names = scalar_method_names + children_method_names
283
288
  if all_method_names.include?(:alias)
284
289
  # Rather than complicating this special case,
285
290
  # let it be overridden (in field)
286
291
  return
287
292
  else
288
293
  arguments = scalar_method_names.map { |m| "#{m}: nil"} +
289
- @children_methods.keys.map { |m| "#{m}: NO_CHILDREN" } +
294
+ children_method_names.map { |m| "#{m}: NO_CHILDREN" } +
290
295
  DEFAULT_INITIALIZE_OPTIONS
291
296
 
292
297
  assignments = scalar_method_names.map { |m| "@#{m} = #{m}"} +
293
- @children_methods.keys.map { |m| "@#{m} = #{m}.freeze" }
298
+ children_method_names.map { |m| "@#{m} = #{m}.freeze" }
294
299
 
295
300
  if name.end_with?("Definition") && name != "FragmentDefinition"
296
301
  arguments << "definition_pos: nil"
@@ -298,7 +303,7 @@ module GraphQL
298
303
  end
299
304
 
300
305
  keywords = scalar_method_names.map { |m| "#{m}: #{m}"} +
301
- @children_methods.keys.map { |m| "#{m}: #{m}" }
306
+ children_method_names.map { |m| "#{m}: #{m}" }
302
307
 
303
308
  module_eval <<-RUBY, __FILE__, __LINE__
304
309
  def initialize(#{arguments.join(", ")})
@@ -306,13 +311,25 @@ module GraphQL
306
311
  @col = col
307
312
  @pos = pos
308
313
  @filename = filename
309
- @source_string = source_string
314
+ @source = source
310
315
  #{assignments.join("\n")}
311
316
  end
312
317
 
313
- def self.from_a(filename, line, col, #{(scalar_method_names + @children_methods.keys).join(", ")})
318
+ def self.from_a(filename, line, col, #{all_method_names.join(", ")})
314
319
  self.new(filename: filename, line: line, col: col, #{keywords.join(", ")})
315
320
  end
321
+
322
+ def marshal_dump
323
+ [
324
+ line, col, # use methods here to force them to be calculated
325
+ @filename,
326
+ #{all_method_names.map { |n| "@#{n}," }.join}
327
+ ]
328
+ end
329
+
330
+ def marshal_load(values)
331
+ @line, @col, @filename #{all_method_names.map { |n| ", @#{n}"}.join} = values
332
+ end
316
333
  RUBY
317
334
  end
318
335
  end
@@ -385,7 +402,7 @@ module GraphQL
385
402
  # @!attribute selections
386
403
  # @return [Array<Nodes::Field>] Selections on this object (or empty array if this is a scalar field)
387
404
 
388
- def initialize(name: nil, arguments: NONE, directives: NONE, selections: NONE, field_alias: nil, line: nil, col: nil, pos: nil, filename: nil, source_string: nil)
405
+ def initialize(name: nil, arguments: NONE, directives: NONE, selections: NONE, field_alias: nil, line: nil, col: nil, pos: nil, filename: nil, source: nil)
389
406
  @name = name
390
407
  @arguments = arguments || NONE
391
408
  @directives = directives || NONE
@@ -396,13 +413,21 @@ module GraphQL
396
413
  @col = col
397
414
  @pos = pos
398
415
  @filename = filename
399
- @source_string = source_string
416
+ @source = source
400
417
  end
401
418
 
402
419
  def self.from_a(filename, line, col, field_alias, name, arguments, directives, selections) # rubocop:disable Metrics/ParameterLists
403
420
  self.new(filename: filename, line: line, col: col, field_alias: field_alias, name: name, arguments: arguments, directives: directives, selections: selections)
404
421
  end
405
422
 
423
+ def marshal_dump
424
+ [line, col, @filename, @name, @arguments, @directives, @selections, @alias]
425
+ end
426
+
427
+ def marshal_load(values)
428
+ @line, @col, @filename, @name, @arguments, @directives, @selections, @alias = values
429
+ end
430
+
406
431
  # Override this because default is `:fields`
407
432
  self.children_method_name = :selections
408
433
  end
@@ -421,14 +446,14 @@ module GraphQL
421
446
 
422
447
  # @!attribute type
423
448
  # @return [String] the type condition for this fragment (name of type which it may apply to)
424
- def initialize(name: nil, type: nil, directives: NONE, selections: NONE, filename: nil, pos: nil, source_string: nil, line: nil, col: nil)
449
+ def initialize(name: nil, type: nil, directives: NONE, selections: NONE, filename: nil, pos: nil, source: nil, line: nil, col: nil)
425
450
  @name = name
426
451
  @type = type
427
452
  @directives = directives
428
453
  @selections = selections
429
454
  @filename = filename
430
455
  @pos = pos
431
- @source_string = source_string
456
+ @source = source
432
457
  @line = line
433
458
  @col = col
434
459
  end
@@ -436,6 +461,14 @@ module GraphQL
436
461
  def self.from_a(filename, line, col, name, type, directives, selections)
437
462
  self.new(filename: filename, line: line, col: col, name: name, type: type, directives: directives, selections: selections)
438
463
  end
464
+
465
+ def marshal_dump
466
+ [line, col, @filename, @name, @type, @directives, @selections]
467
+ end
468
+
469
+ def marshal_load(values)
470
+ @line, @col, @filename, @name, @type, @directives, @selections = values
471
+ end
439
472
  end
440
473
 
441
474
  # Application of a named fragment in a selection
@@ -36,6 +36,7 @@ module GraphQL
36
36
  @filename = filename
37
37
  @trace = trace
38
38
  @dedup_identifiers = false
39
+ @lines_at = nil
39
40
  end
40
41
 
41
42
  def parse
@@ -48,9 +49,43 @@ module GraphQL
48
49
  end
49
50
  end
50
51
 
52
+ def line_at(pos)
53
+ line = lines_at.bsearch_index { |l| l >= pos }
54
+ if line.nil?
55
+ @lines_at.size + 1
56
+ else
57
+ line + 1
58
+ end
59
+ end
60
+
61
+ def column_at(pos)
62
+ next_line_idx = lines_at.bsearch_index { |l| l >= pos } || 0
63
+ if next_line_idx > 0
64
+ line_pos = @lines_at[next_line_idx - 1]
65
+ pos - line_pos
66
+ else
67
+ pos + 1
68
+ end
69
+ end
51
70
 
52
71
  private
53
72
 
73
+ # @return [Array<Integer>] Positions of each line break in the original string
74
+ def lines_at
75
+ @lines_at ||= begin
76
+ la = []
77
+ idx = 0
78
+ while idx
79
+ idx = @graphql_str.index("\n", idx)
80
+ if idx
81
+ la << idx
82
+ idx += 1
83
+ end
84
+ end
85
+ la
86
+ end
87
+ end
88
+
54
89
  attr_reader :token_name
55
90
 
56
91
  def advance_token
@@ -73,7 +108,7 @@ module GraphQL
73
108
  while !@lexer.eos?
74
109
  defns << definition
75
110
  end
76
- Document.new(pos: 0, definitions: defns, filename: @filename, source_string: @graphql_str)
111
+ Document.new(pos: 0, definitions: defns, filename: @filename, source: self)
77
112
  end
78
113
 
79
114
  def definition
@@ -95,7 +130,7 @@ module GraphQL
95
130
  directives: directives,
96
131
  selections: selections,
97
132
  filename: @filename,
98
- source_string: @graphql_str
133
+ source: self
99
134
  )
100
135
  when :QUERY, :MUTATION, :SUBSCRIPTION, :LCURLY
101
136
  op_loc = pos
@@ -131,7 +166,7 @@ module GraphQL
131
166
  default_value: default_value,
132
167
  directives: directives,
133
168
  filename: @filename,
134
- source_string: @graphql_str
169
+ source: self
135
170
  )
136
171
  end
137
172
  expect_token(:RPAREN)
@@ -150,7 +185,7 @@ module GraphQL
150
185
  directives: directives,
151
186
  selections: selection_set,
152
187
  filename: @filename,
153
- source_string: @graphql_str
188
+ source: self
154
189
  )
155
190
  when :EXTEND
156
191
  loc = pos
@@ -160,7 +195,7 @@ module GraphQL
160
195
  advance_token
161
196
  name = parse_name
162
197
  directives = parse_directives
163
- ScalarTypeExtension.new(pos: loc, name: name, directives: directives, filename: @filename, source_string: @graphql_str)
198
+ ScalarTypeExtension.new(pos: loc, name: name, directives: directives, filename: @filename, source: self)
164
199
  when :TYPE
165
200
  advance_token
166
201
  name = parse_name
@@ -168,32 +203,32 @@ module GraphQL
168
203
  directives = parse_directives
169
204
  field_defns = at?(:LCURLY) ? parse_field_definitions : EMPTY_ARRAY
170
205
 
171
- ObjectTypeExtension.new(pos: loc, name: name, interfaces: implements_interfaces, directives: directives, fields: field_defns, filename: @filename, source_string: @graphql_str)
206
+ ObjectTypeExtension.new(pos: loc, name: name, interfaces: implements_interfaces, directives: directives, fields: field_defns, filename: @filename, source: self)
172
207
  when :INTERFACE
173
208
  advance_token
174
209
  name = parse_name
175
210
  directives = parse_directives
176
211
  interfaces = parse_implements
177
212
  fields_definition = at?(:LCURLY) ? parse_field_definitions : EMPTY_ARRAY
178
- InterfaceTypeExtension.new(pos: loc, name: name, directives: directives, fields: fields_definition, interfaces: interfaces, filename: @filename, source_string: @graphql_str)
213
+ InterfaceTypeExtension.new(pos: loc, name: name, directives: directives, fields: fields_definition, interfaces: interfaces, filename: @filename, source: self)
179
214
  when :UNION
180
215
  advance_token
181
216
  name = parse_name
182
217
  directives = parse_directives
183
218
  union_member_types = parse_union_members
184
- UnionTypeExtension.new(pos: loc, name: name, directives: directives, types: union_member_types, filename: @filename, source_string: @graphql_str)
219
+ UnionTypeExtension.new(pos: loc, name: name, directives: directives, types: union_member_types, filename: @filename, source: self)
185
220
  when :ENUM
186
221
  advance_token
187
222
  name = parse_name
188
223
  directives = parse_directives
189
224
  enum_values_definition = parse_enum_value_definitions
190
- Nodes::EnumTypeExtension.new(pos: loc, name: name, directives: directives, values: enum_values_definition, filename: @filename, source_string: @graphql_str)
225
+ Nodes::EnumTypeExtension.new(pos: loc, name: name, directives: directives, values: enum_values_definition, filename: @filename, source: self)
191
226
  when :INPUT
192
227
  advance_token
193
228
  name = parse_name
194
229
  directives = parse_directives
195
230
  input_fields_definition = parse_input_object_field_definitions
196
- InputObjectTypeExtension.new(pos: loc, name: name, directives: directives, fields: input_fields_definition, filename: @filename, source_string: @graphql_str)
231
+ InputObjectTypeExtension.new(pos: loc, name: name, directives: directives, fields: input_fields_definition, filename: @filename, source: self)
197
232
  when :SCHEMA
198
233
  advance_token
199
234
  directives = parse_directives
@@ -226,7 +261,7 @@ module GraphQL
226
261
  directives: directives,
227
262
  pos: loc,
228
263
  filename: @filename,
229
- source_string: @graphql_str,
264
+ source: self,
230
265
  )
231
266
  else
232
267
  expect_one_of([:SCHEMA, :SCALAR, :TYPE, :ENUM, :INPUT, :UNION, :INTERFACE])
@@ -259,7 +294,7 @@ module GraphQL
259
294
  end
260
295
  end
261
296
  expect_token :RCURLY
262
- SchemaDefinition.new(pos: loc, definition_pos: defn_loc, query: query, mutation: mutation, subscription: subscription, directives: directives, filename: @filename, source_string: @graphql_str)
297
+ SchemaDefinition.new(pos: loc, definition_pos: defn_loc, query: query, mutation: mutation, subscription: subscription, directives: directives, filename: @filename, source: self)
263
298
  when :DIRECTIVE
264
299
  advance_token
265
300
  expect_token :DIR_SIGN
@@ -272,12 +307,12 @@ module GraphQL
272
307
  false
273
308
  end
274
309
  expect_token :ON
275
- directive_locations = [DirectiveLocation.new(pos: pos, name: parse_name, filename: @filename, source_string: @graphql_str)]
310
+ directive_locations = [DirectiveLocation.new(pos: pos, name: parse_name, filename: @filename, source: self)]
276
311
  while at?(:PIPE)
277
312
  advance_token
278
- directive_locations << DirectiveLocation.new(pos: pos, name: parse_name, filename: @filename, source_string: @graphql_str)
313
+ directive_locations << DirectiveLocation.new(pos: pos, name: parse_name, filename: @filename, source: self)
279
314
  end
280
- DirectiveDefinition.new(pos: loc, definition_pos: defn_loc, description: desc, name: name, arguments: arguments_definition, locations: directive_locations, repeatable: repeatable, filename: @filename, source_string: @graphql_str)
315
+ DirectiveDefinition.new(pos: loc, definition_pos: defn_loc, description: desc, name: name, arguments: arguments_definition, locations: directive_locations, repeatable: repeatable, filename: @filename, source: self)
281
316
  when :TYPE
282
317
  advance_token
283
318
  name = parse_name
@@ -285,37 +320,37 @@ module GraphQL
285
320
  directives = parse_directives
286
321
  field_defns = at?(:LCURLY) ? parse_field_definitions : EMPTY_ARRAY
287
322
 
288
- ObjectTypeDefinition.new(pos: loc, definition_pos: defn_loc, description: desc, name: name, interfaces: implements_interfaces, directives: directives, fields: field_defns, filename: @filename, source_string: @graphql_str)
323
+ ObjectTypeDefinition.new(pos: loc, definition_pos: defn_loc, description: desc, name: name, interfaces: implements_interfaces, directives: directives, fields: field_defns, filename: @filename, source: self)
289
324
  when :INTERFACE
290
325
  advance_token
291
326
  name = parse_name
292
327
  interfaces = parse_implements
293
328
  directives = parse_directives
294
329
  fields_definition = parse_field_definitions
295
- InterfaceTypeDefinition.new(pos: loc, definition_pos: defn_loc, description: desc, name: name, directives: directives, fields: fields_definition, interfaces: interfaces, filename: @filename, source_string: @graphql_str)
330
+ InterfaceTypeDefinition.new(pos: loc, definition_pos: defn_loc, description: desc, name: name, directives: directives, fields: fields_definition, interfaces: interfaces, filename: @filename, source: self)
296
331
  when :UNION
297
332
  advance_token
298
333
  name = parse_name
299
334
  directives = parse_directives
300
335
  union_member_types = parse_union_members
301
- UnionTypeDefinition.new(pos: loc, definition_pos: defn_loc, description: desc, name: name, directives: directives, types: union_member_types, filename: @filename, source_string: @graphql_str)
336
+ UnionTypeDefinition.new(pos: loc, definition_pos: defn_loc, description: desc, name: name, directives: directives, types: union_member_types, filename: @filename, source: self)
302
337
  when :SCALAR
303
338
  advance_token
304
339
  name = parse_name
305
340
  directives = parse_directives
306
- ScalarTypeDefinition.new(pos: loc, definition_pos: defn_loc, description: desc, name: name, directives: directives, filename: @filename, source_string: @graphql_str)
341
+ ScalarTypeDefinition.new(pos: loc, definition_pos: defn_loc, description: desc, name: name, directives: directives, filename: @filename, source: self)
307
342
  when :ENUM
308
343
  advance_token
309
344
  name = parse_name
310
345
  directives = parse_directives
311
346
  enum_values_definition = parse_enum_value_definitions
312
- Nodes::EnumTypeDefinition.new(pos: loc, definition_pos: defn_loc, description: desc, name: name, directives: directives, values: enum_values_definition, filename: @filename, source_string: @graphql_str)
347
+ Nodes::EnumTypeDefinition.new(pos: loc, definition_pos: defn_loc, description: desc, name: name, directives: directives, values: enum_values_definition, filename: @filename, source: self)
313
348
  when :INPUT
314
349
  advance_token
315
350
  name = parse_name
316
351
  directives = parse_directives
317
352
  input_fields_definition = parse_input_object_field_definitions
318
- InputObjectTypeDefinition.new(pos: loc, definition_pos: defn_loc, description: desc, name: name, directives: directives, fields: input_fields_definition, filename: @filename, source_string: @graphql_str)
353
+ InputObjectTypeDefinition.new(pos: loc, definition_pos: defn_loc, description: desc, name: name, directives: directives, fields: input_fields_definition, filename: @filename, source: self)
319
354
  else
320
355
  expect_one_of([:SCHEMA, :SCALAR, :TYPE, :ENUM, :INPUT, :UNION, :INTERFACE])
321
356
  end
@@ -346,7 +381,7 @@ module GraphQL
346
381
  defn_loc = pos
347
382
  enum_value = parse_enum_name
348
383
  v_directives = parse_directives
349
- list << EnumValueDefinition.new(pos: v_loc, definition_pos: defn_loc, description: description, name: enum_value, directives: v_directives, filename: @filename, source_string: @graphql_str)
384
+ list << EnumValueDefinition.new(pos: v_loc, definition_pos: defn_loc, description: description, name: enum_value, directives: v_directives, filename: @filename, source: self)
350
385
  end
351
386
  expect_token :RCURLY
352
387
  list
@@ -397,7 +432,7 @@ module GraphQL
397
432
  type = self.type
398
433
  directives = parse_directives
399
434
 
400
- list << FieldDefinition.new(pos: loc, definition_pos: defn_loc, description: description, name: name, arguments: arguments_definition, type: type, directives: directives, filename: @filename, source_string: @graphql_str)
435
+ list << FieldDefinition.new(pos: loc, definition_pos: defn_loc, description: description, name: name, arguments: arguments_definition, type: type, directives: directives, filename: @filename, source: self)
401
436
  end
402
437
  expect_token :RCURLY
403
438
  list
@@ -431,7 +466,7 @@ module GraphQL
431
466
  nil
432
467
  end
433
468
  directives = parse_directives
434
- InputValueDefinition.new(pos: loc, definition_pos: defn_loc, description: description, name: name, type: type, default_value: default_value, directives: directives, filename: @filename, source_string: @graphql_str)
469
+ InputValueDefinition.new(pos: loc, definition_pos: defn_loc, description: description, name: name, type: type, default_value: default_value, directives: directives, filename: @filename, source: self)
435
470
  end
436
471
 
437
472
  def type
@@ -443,7 +478,7 @@ module GraphQL
443
478
  end
444
479
 
445
480
  if at?(:BANG)
446
- type = Nodes::NonNullType.new(pos: pos, of_type: type)
481
+ type = Nodes::NonNullType.new(pos: pos, of_type: type, source: self)
447
482
  expect_token(:BANG)
448
483
  end
449
484
  type
@@ -452,7 +487,7 @@ module GraphQL
452
487
  def list_type
453
488
  loc = pos
454
489
  expect_token(:LBRACKET)
455
- type = Nodes::ListType.new(pos: loc, of_type: self.type)
490
+ type = Nodes::ListType.new(pos: loc, of_type: self.type, source: self)
456
491
  expect_token(:RBRACKET)
457
492
  type
458
493
  end
@@ -489,7 +524,7 @@ module GraphQL
489
524
 
490
525
  directives = parse_directives
491
526
 
492
- Nodes::InlineFragment.new(pos: loc, type: if_type, directives: directives, selections: selection_set, filename: @filename, source_string: @graphql_str)
527
+ Nodes::InlineFragment.new(pos: loc, type: if_type, directives: directives, selections: selection_set, filename: @filename, source: self)
493
528
  else
494
529
  name = parse_name_without_on
495
530
  directives = parse_directives
@@ -497,7 +532,7 @@ module GraphQL
497
532
  # Can this ever happen?
498
533
  # expect_token(:IDENTIFIER) if at?(:ON)
499
534
 
500
- FragmentSpread.new(pos: loc, name: name, directives: directives, filename: @filename, source_string: @graphql_str)
535
+ FragmentSpread.new(pos: loc, name: name, directives: directives, filename: @filename, source: self)
501
536
  end
502
537
  else
503
538
  loc = pos
@@ -515,7 +550,7 @@ module GraphQL
515
550
  directives = at?(:DIR_SIGN) ? parse_directives : nil
516
551
  selection_set = at?(:LCURLY) ? self.selection_set : nil
517
552
 
518
- Nodes::Field.new(pos: loc, field_alias: field_alias, name: name, arguments: arguments, directives: directives, selections: selection_set, filename: @filename, source_string: @graphql_str)
553
+ Nodes::Field.new(pos: loc, field_alias: field_alias, name: name, arguments: arguments, directives: directives, selections: selection_set, filename: @filename, source: self)
519
554
  end
520
555
  end
521
556
  expect_token(:RCURLY)
@@ -609,7 +644,7 @@ module GraphQL
609
644
  end
610
645
 
611
646
  def parse_type_name
612
- TypeName.new(pos: pos, name: parse_name, filename: @filename, source_string: @graphql_str)
647
+ TypeName.new(pos: pos, name: parse_name, filename: @filename, source: self)
613
648
  end
614
649
 
615
650
  def parse_directives
@@ -621,7 +656,7 @@ module GraphQL
621
656
  name = parse_name
622
657
  arguments = parse_arguments
623
658
 
624
- dirs << Nodes::Directive.new(pos: loc, name: name, arguments: arguments, filename: @filename, source_string: @graphql_str)
659
+ dirs << Nodes::Directive.new(pos: loc, name: name, arguments: arguments, filename: @filename, source: self)
625
660
  end
626
661
  dirs
627
662
  else
@@ -637,7 +672,7 @@ module GraphQL
637
672
  loc = pos
638
673
  name = parse_name
639
674
  expect_token(:COLON)
640
- args << Nodes::Argument.new(pos: loc, name: name, value: value, filename: @filename, source_string: @graphql_str)
675
+ args << Nodes::Argument.new(pos: loc, name: name, value: value, filename: @filename, source: self)
641
676
  end
642
677
  if args.empty?
643
678
  expect_token(:ARGUMENT_NAME) # At least one argument is required
@@ -671,9 +706,9 @@ module GraphQL
671
706
  false
672
707
  when :NULL
673
708
  advance_token
674
- NullValue.new(pos: pos, name: "null", filename: @filename, source_string: @graphql_str)
709
+ NullValue.new(pos: pos, name: "null", filename: @filename, source: self)
675
710
  when :IDENTIFIER
676
- Nodes::Enum.new(pos: pos, name: expect_token_value(:IDENTIFIER), filename: @filename, source_string: @graphql_str)
711
+ Nodes::Enum.new(pos: pos, name: expect_token_value(:IDENTIFIER), filename: @filename, source: self)
677
712
  when :LBRACKET
678
713
  advance_token
679
714
  list = []
@@ -690,14 +725,14 @@ module GraphQL
690
725
  loc = pos
691
726
  n = parse_name
692
727
  expect_token(:COLON)
693
- args << Argument.new(pos: loc, name: n, value: value, filename: @filename, source_string: @graphql_str)
728
+ args << Argument.new(pos: loc, name: n, value: value, filename: @filename, source: self)
694
729
  end
695
730
  expect_token(:RCURLY)
696
- InputObject.new(pos: start, arguments: args, filename: @filename, source_string: @graphql_str)
731
+ InputObject.new(pos: start, arguments: args, filename: @filename, source: self)
697
732
  when :VAR_SIGN
698
733
  loc = pos
699
734
  advance_token
700
- VariableIdentifier.new(pos: loc, name: parse_name, filename: @filename, source_string: @graphql_str)
735
+ VariableIdentifier.new(pos: loc, name: parse_name, filename: @filename, source: self)
701
736
  else
702
737
  expect_token(:VALUE)
703
738
  end
data/lib/graphql/query.rb CHANGED
@@ -304,7 +304,7 @@ module GraphQL
304
304
 
305
305
  # @return [String] An opaque hash for identifying this query's given query string and selected operation
306
306
  def operation_fingerprint
307
- @operation_fingerprint ||= "#{selected_operation_name || "anonymous"}/#{Fingerprint.generate(query_string)}"
307
+ @operation_fingerprint ||= "#{selected_operation_name || "anonymous"}/#{Fingerprint.generate(query_string || "")}"
308
308
  end
309
309
 
310
310
  # @return [String] An opaque hash for identifying this query's given a variable values (not including defaults)
@@ -749,9 +749,10 @@ module GraphQL
749
749
 
750
750
  attr_writer :max_complexity
751
751
 
752
- def max_complexity(max_complexity = nil)
752
+ def max_complexity(max_complexity = nil, count_introspection_fields: true)
753
753
  if max_complexity
754
754
  @max_complexity = max_complexity
755
+ @max_complexity_count_introspection_fields = count_introspection_fields
755
756
  elsif defined?(@max_complexity)
756
757
  @max_complexity
757
758
  else
@@ -759,6 +760,14 @@ module GraphQL
759
760
  end
760
761
  end
761
762
 
763
+ def max_complexity_count_introspection_fields
764
+ if defined?(@max_complexity_count_introspection_fields)
765
+ @max_complexity_count_introspection_fields
766
+ else
767
+ find_inherited_value(:max_complexity_count_introspection_fields, true)
768
+ end
769
+ end
770
+
762
771
  attr_writer :analysis_engine
763
772
 
764
773
  def analysis_engine
@@ -25,33 +25,33 @@ module GraphQL
25
25
  }.each do |trace_method, platform_key|
26
26
  module_eval <<-RUBY, __FILE__, __LINE__
27
27
  def #{trace_method}(**data)
28
- instrument_execution("#{platform_key}", "#{trace_method}") { super }
28
+ instrument_prometheus_execution("#{platform_key}", "#{trace_method}") { super }
29
29
  end
30
30
  RUBY
31
31
  end
32
32
 
33
33
  def platform_execute_field(platform_key, &block)
34
- instrument_execution(platform_key, "execute_field", &block)
34
+ instrument_prometheus_execution(platform_key, "execute_field", &block)
35
35
  end
36
36
 
37
37
  def platform_execute_field_lazy(platform_key, &block)
38
- instrument_execution(platform_key, "execute_field_lazy", &block)
38
+ instrument_prometheus_execution(platform_key, "execute_field_lazy", &block)
39
39
  end
40
40
 
41
41
  def platform_authorized(platform_key, &block)
42
- instrument_execution(platform_key, "authorized", &block)
42
+ instrument_prometheus_execution(platform_key, "authorized", &block)
43
43
  end
44
44
 
45
45
  def platform_authorized_lazy(platform_key, &block)
46
- instrument_execution(platform_key, "authorized_lazy", &block)
46
+ instrument_prometheus_execution(platform_key, "authorized_lazy", &block)
47
47
  end
48
48
 
49
49
  def platform_resolve_type(platform_key, &block)
50
- instrument_execution(platform_key, "resolve_type", &block)
50
+ instrument_prometheus_execution(platform_key, "resolve_type", &block)
51
51
  end
52
52
 
53
53
  def platform_resolve_type_lazy(platform_key, &block)
54
- instrument_execution(platform_key, "resolve_type_lazy", &block)
54
+ instrument_prometheus_execution(platform_key, "resolve_type_lazy", &block)
55
55
  end
56
56
 
57
57
  def platform_field_key(field)
@@ -68,7 +68,7 @@ module GraphQL
68
68
 
69
69
  private
70
70
 
71
- def instrument_execution(platform_key, key, &block)
71
+ def instrument_prometheus_execution(platform_key, key, &block)
72
72
  if @keys_whitelist.include?(key)
73
73
  start = ::Process.clock_gettime ::Process::CLOCK_MONOTONIC
74
74
  result = block.call
@@ -12,7 +12,7 @@ module GraphQL
12
12
  @set_transaction_name = set_transaction_name
13
13
  super
14
14
  end
15
-
15
+
16
16
  def execute_query(**data)
17
17
  set_this_txn_name = data[:query].context[:set_sentry_transaction_name]
18
18
  if set_this_txn_name == true || (set_this_txn_name.nil? && @set_transaction_name)
@@ -20,7 +20,7 @@ module GraphQL
20
20
  scope.set_transaction_name(transaction_name(data[:query]))
21
21
  end
22
22
  end
23
- instrument_execution("graphql.execute", "execute_query", data) { super }
23
+ instrument_sentry_execution("graphql.execute", "execute_query", data) { super }
24
24
  end
25
25
 
26
26
  {
@@ -34,33 +34,33 @@ module GraphQL
34
34
  }.each do |trace_method, platform_key|
35
35
  module_eval <<-RUBY, __FILE__, __LINE__
36
36
  def #{trace_method}(**data)
37
- instrument_execution("#{platform_key}", "#{trace_method}", data) { super }
37
+ instrument_sentry_execution("#{platform_key}", "#{trace_method}", data) { super }
38
38
  end
39
39
  RUBY
40
40
  end
41
41
 
42
42
  def platform_execute_field(platform_key, &block)
43
- instrument_execution(platform_key, "execute_field", &block)
43
+ instrument_sentry_execution(platform_key, "execute_field", &block)
44
44
  end
45
45
 
46
46
  def platform_execute_field_lazy(platform_key, &block)
47
- instrument_execution(platform_key, "execute_field_lazy", &block)
47
+ instrument_sentry_execution(platform_key, "execute_field_lazy", &block)
48
48
  end
49
49
 
50
50
  def platform_authorized(platform_key, &block)
51
- instrument_execution(platform_key, "authorized", &block)
51
+ instrument_sentry_execution(platform_key, "authorized", &block)
52
52
  end
53
53
 
54
54
  def platform_authorized_lazy(platform_key, &block)
55
- instrument_execution(platform_key, "authorized_lazy", &block)
55
+ instrument_sentry_execution(platform_key, "authorized_lazy", &block)
56
56
  end
57
57
 
58
58
  def platform_resolve_type(platform_key, &block)
59
- instrument_execution(platform_key, "resolve_type", &block)
59
+ instrument_sentry_execution(platform_key, "resolve_type", &block)
60
60
  end
61
61
 
62
62
  def platform_resolve_type_lazy(platform_key, &block)
63
- instrument_execution(platform_key, "resolve_type_lazy", &block)
63
+ instrument_sentry_execution(platform_key, "resolve_type_lazy", &block)
64
64
  end
65
65
 
66
66
  def platform_field_key(field)
@@ -77,7 +77,7 @@ module GraphQL
77
77
 
78
78
  private
79
79
 
80
- def instrument_execution(platform_key, trace_method, data=nil, &block)
80
+ def instrument_sentry_execution(platform_key, trace_method, data=nil, &block)
81
81
  return yield unless Sentry.initialized?
82
82
 
83
83
  Sentry.with_child_span(op: platform_key, start_timestamp: Sentry.utc_now.to_f) do |span|
@@ -1,4 +1,4 @@
1
1
  # frozen_string_literal: true
2
2
  module GraphQL
3
- VERSION = "2.3.2"
3
+ VERSION = "2.3.4"
4
4
  end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: graphql
3
3
  version: !ruby/object:Gem::Version
4
- version: 2.3.2
4
+ version: 2.3.4
5
5
  platform: ruby
6
6
  authors:
7
7
  - Robert Mosolgo
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2024-04-26 00:00:00.000000000 Z
11
+ date: 2024-05-21 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: base64