graphql 2.3.2 → 2.3.4

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
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