graphql 1.13.17 → 2.0.20

Sign up to get free protection for your applications and to get access to all the features.
Files changed (260) hide show
  1. checksums.yaml +4 -4
  2. data/lib/generators/graphql/install_generator.rb +1 -1
  3. data/lib/generators/graphql/relay.rb +3 -17
  4. data/lib/generators/graphql/templates/schema.erb +3 -0
  5. data/lib/graphql/analysis/ast/field_usage.rb +3 -1
  6. data/lib/graphql/analysis/ast/max_query_complexity.rb +0 -1
  7. data/lib/graphql/analysis/ast/query_complexity.rb +1 -1
  8. data/lib/graphql/analysis/ast/query_depth.rb +0 -1
  9. data/lib/graphql/analysis/ast/visitor.rb +43 -36
  10. data/lib/graphql/analysis/ast.rb +2 -12
  11. data/lib/graphql/analysis.rb +0 -7
  12. data/lib/graphql/backtrace/table.rb +2 -20
  13. data/lib/graphql/backtrace/tracer.rb +2 -3
  14. data/lib/graphql/backtrace.rb +2 -8
  15. data/lib/graphql/dataloader/null_dataloader.rb +3 -1
  16. data/lib/graphql/dataloader/source.rb +9 -0
  17. data/lib/graphql/dataloader.rb +4 -1
  18. data/lib/graphql/dig.rb +1 -1
  19. data/lib/graphql/execution/errors.rb +12 -82
  20. data/lib/graphql/execution/interpreter/resolve.rb +26 -0
  21. data/lib/graphql/execution/interpreter/runtime.rb +159 -120
  22. data/lib/graphql/execution/interpreter.rb +187 -78
  23. data/lib/graphql/execution/lazy.rb +7 -21
  24. data/lib/graphql/execution/lookahead.rb +44 -40
  25. data/lib/graphql/execution/multiplex.rb +3 -174
  26. data/lib/graphql/execution.rb +11 -4
  27. data/lib/graphql/introspection/directive_type.rb +2 -2
  28. data/lib/graphql/introspection/dynamic_fields.rb +3 -8
  29. data/lib/graphql/introspection/entry_points.rb +2 -15
  30. data/lib/graphql/introspection/field_type.rb +1 -1
  31. data/lib/graphql/introspection/schema_type.rb +2 -2
  32. data/lib/graphql/introspection/type_type.rb +13 -6
  33. data/lib/graphql/introspection.rb +4 -3
  34. data/lib/graphql/language/document_from_schema_definition.rb +18 -35
  35. data/lib/graphql/language/lexer.rb +216 -1488
  36. data/lib/graphql/language/nodes.rb +65 -39
  37. data/lib/graphql/language/parser.rb +376 -364
  38. data/lib/graphql/language/parser.y +49 -44
  39. data/lib/graphql/language/printer.rb +37 -21
  40. data/lib/graphql/language/visitor.rb +191 -83
  41. data/lib/graphql/pagination/active_record_relation_connection.rb +0 -8
  42. data/lib/graphql/pagination/array_connection.rb +4 -2
  43. data/lib/graphql/pagination/connection.rb +31 -4
  44. data/lib/graphql/pagination/connections.rb +3 -28
  45. data/lib/graphql/pagination/relation_connection.rb +2 -0
  46. data/lib/graphql/query/context.rb +155 -196
  47. data/lib/graphql/query/input_validation_result.rb +1 -1
  48. data/lib/graphql/query/null_context.rb +0 -3
  49. data/lib/graphql/query/validation_pipeline.rb +10 -34
  50. data/lib/graphql/query/variables.rb +7 -20
  51. data/lib/graphql/query.rb +32 -42
  52. data/lib/graphql/railtie.rb +0 -104
  53. data/lib/graphql/rake_task/validate.rb +1 -1
  54. data/lib/graphql/rake_task.rb +29 -1
  55. data/lib/graphql/relay/range_add.rb +9 -20
  56. data/lib/graphql/relay.rb +0 -15
  57. data/lib/graphql/schema/addition.rb +7 -9
  58. data/lib/graphql/schema/argument.rb +36 -43
  59. data/lib/graphql/schema/build_from_definition.rb +32 -18
  60. data/lib/graphql/schema/directive/one_of.rb +12 -0
  61. data/lib/graphql/schema/directive/transform.rb +1 -1
  62. data/lib/graphql/schema/directive.rb +12 -23
  63. data/lib/graphql/schema/enum.rb +28 -39
  64. data/lib/graphql/schema/enum_value.rb +5 -25
  65. data/lib/graphql/schema/field/connection_extension.rb +4 -0
  66. data/lib/graphql/schema/field.rb +237 -339
  67. data/lib/graphql/schema/input_object.rb +56 -67
  68. data/lib/graphql/schema/interface.rb +0 -35
  69. data/lib/graphql/schema/introspection_system.rb +3 -8
  70. data/lib/graphql/schema/late_bound_type.rb +8 -2
  71. data/lib/graphql/schema/list.rb +0 -6
  72. data/lib/graphql/schema/loader.rb +1 -2
  73. data/lib/graphql/schema/member/base_dsl_methods.rb +17 -19
  74. data/lib/graphql/schema/member/build_type.rb +5 -7
  75. data/lib/graphql/schema/member/has_arguments.rb +146 -55
  76. data/lib/graphql/schema/member/has_ast_node.rb +12 -0
  77. data/lib/graphql/schema/member/has_deprecation_reason.rb +3 -4
  78. data/lib/graphql/schema/member/has_directives.rb +81 -59
  79. data/lib/graphql/schema/member/has_fields.rb +17 -4
  80. data/lib/graphql/schema/member/has_interfaces.rb +49 -10
  81. data/lib/graphql/schema/member/has_validators.rb +31 -5
  82. data/lib/graphql/schema/member/relay_shortcuts.rb +47 -2
  83. data/lib/graphql/schema/member/type_system_helpers.rb +17 -0
  84. data/lib/graphql/schema/member/validates_input.rb +1 -1
  85. data/lib/graphql/schema/member.rb +0 -6
  86. data/lib/graphql/schema/mutation.rb +0 -9
  87. data/lib/graphql/schema/non_null.rb +1 -7
  88. data/lib/graphql/schema/object.rb +15 -52
  89. data/lib/graphql/schema/relay_classic_mutation.rb +53 -42
  90. data/lib/graphql/schema/resolver/has_payload_type.rb +20 -10
  91. data/lib/graphql/schema/resolver.rb +41 -42
  92. data/lib/graphql/schema/scalar.rb +7 -22
  93. data/lib/graphql/schema/subscription.rb +0 -7
  94. data/lib/graphql/schema/timeout.rb +24 -28
  95. data/lib/graphql/schema/type_membership.rb +3 -0
  96. data/lib/graphql/schema/union.rb +10 -17
  97. data/lib/graphql/schema/warden.rb +34 -8
  98. data/lib/graphql/schema/wrapper.rb +0 -5
  99. data/lib/graphql/schema.rb +241 -973
  100. data/lib/graphql/static_validation/all_rules.rb +1 -0
  101. data/lib/graphql/static_validation/base_visitor.rb +4 -21
  102. data/lib/graphql/static_validation/definition_dependencies.rb +7 -1
  103. data/lib/graphql/static_validation/error.rb +2 -2
  104. data/lib/graphql/static_validation/literal_validator.rb +19 -1
  105. data/lib/graphql/static_validation/rules/directives_are_defined.rb +11 -5
  106. data/lib/graphql/static_validation/rules/directives_are_in_valid_locations.rb +12 -12
  107. data/lib/graphql/static_validation/rules/one_of_input_objects_are_valid.rb +66 -0
  108. data/lib/graphql/static_validation/rules/one_of_input_objects_are_valid_error.rb +29 -0
  109. data/lib/graphql/static_validation/rules/unique_directives_per_location.rb +12 -6
  110. data/lib/graphql/static_validation/rules/variable_default_values_are_correctly_typed.rb +1 -1
  111. data/lib/graphql/static_validation/validator.rb +3 -25
  112. data/lib/graphql/static_validation.rb +0 -2
  113. data/lib/graphql/subscriptions/action_cable_subscriptions.rb +7 -1
  114. data/lib/graphql/subscriptions/default_subscription_resolve_extension.rb +38 -1
  115. data/lib/graphql/subscriptions/event.rb +3 -8
  116. data/lib/graphql/subscriptions/instrumentation.rb +0 -51
  117. data/lib/graphql/subscriptions.rb +32 -20
  118. data/lib/graphql/tracing/active_support_notifications_trace.rb +16 -0
  119. data/lib/graphql/tracing/appoptics_trace.rb +231 -0
  120. data/lib/graphql/tracing/appsignal_trace.rb +71 -0
  121. data/lib/graphql/tracing/data_dog_trace.rb +148 -0
  122. data/lib/graphql/tracing/data_dog_tracing.rb +2 -0
  123. data/lib/graphql/tracing/new_relic_trace.rb +75 -0
  124. data/lib/graphql/tracing/notifications_trace.rb +41 -0
  125. data/lib/graphql/tracing/platform_trace.rb +107 -0
  126. data/lib/graphql/tracing/platform_tracing.rb +26 -40
  127. data/lib/graphql/tracing/prometheus_trace.rb +89 -0
  128. data/lib/graphql/tracing/prometheus_tracing.rb +3 -3
  129. data/lib/graphql/tracing/scout_trace.rb +72 -0
  130. data/lib/graphql/tracing/statsd_trace.rb +56 -0
  131. data/lib/graphql/tracing.rb +136 -40
  132. data/lib/graphql/type_kinds.rb +6 -3
  133. data/lib/graphql/types/iso_8601_date.rb +4 -1
  134. data/lib/graphql/types/iso_8601_date_time.rb +4 -0
  135. data/lib/graphql/types/relay/base_connection.rb +16 -6
  136. data/lib/graphql/types/relay/connection_behaviors.rb +29 -27
  137. data/lib/graphql/types/relay/edge_behaviors.rb +16 -5
  138. data/lib/graphql/types/relay/node_behaviors.rb +12 -2
  139. data/lib/graphql/types/relay/page_info_behaviors.rb +7 -2
  140. data/lib/graphql/types/relay.rb +0 -3
  141. data/lib/graphql/types/string.rb +1 -1
  142. data/lib/graphql/version.rb +1 -1
  143. data/lib/graphql.rb +13 -74
  144. metadata +30 -133
  145. data/lib/graphql/analysis/analyze_query.rb +0 -98
  146. data/lib/graphql/analysis/field_usage.rb +0 -45
  147. data/lib/graphql/analysis/max_query_complexity.rb +0 -26
  148. data/lib/graphql/analysis/max_query_depth.rb +0 -26
  149. data/lib/graphql/analysis/query_complexity.rb +0 -88
  150. data/lib/graphql/analysis/query_depth.rb +0 -43
  151. data/lib/graphql/analysis/reducer_state.rb +0 -48
  152. data/lib/graphql/argument.rb +0 -131
  153. data/lib/graphql/authorization.rb +0 -82
  154. data/lib/graphql/backtrace/legacy_tracer.rb +0 -56
  155. data/lib/graphql/backwards_compatibility.rb +0 -61
  156. data/lib/graphql/base_type.rb +0 -232
  157. data/lib/graphql/boolean_type.rb +0 -2
  158. data/lib/graphql/compatibility/execution_specification/counter_schema.rb +0 -53
  159. data/lib/graphql/compatibility/execution_specification/specification_schema.rb +0 -200
  160. data/lib/graphql/compatibility/execution_specification.rb +0 -436
  161. data/lib/graphql/compatibility/lazy_execution_specification/lazy_schema.rb +0 -111
  162. data/lib/graphql/compatibility/lazy_execution_specification.rb +0 -215
  163. data/lib/graphql/compatibility/query_parser_specification/parse_error_specification.rb +0 -87
  164. data/lib/graphql/compatibility/query_parser_specification/query_assertions.rb +0 -79
  165. data/lib/graphql/compatibility/query_parser_specification.rb +0 -266
  166. data/lib/graphql/compatibility/schema_parser_specification.rb +0 -682
  167. data/lib/graphql/compatibility.rb +0 -5
  168. data/lib/graphql/define/assign_argument.rb +0 -12
  169. data/lib/graphql/define/assign_connection.rb +0 -13
  170. data/lib/graphql/define/assign_enum_value.rb +0 -18
  171. data/lib/graphql/define/assign_global_id_field.rb +0 -11
  172. data/lib/graphql/define/assign_mutation_function.rb +0 -34
  173. data/lib/graphql/define/assign_object_field.rb +0 -42
  174. data/lib/graphql/define/defined_object_proxy.rb +0 -53
  175. data/lib/graphql/define/instance_definable.rb +0 -255
  176. data/lib/graphql/define/no_definition_error.rb +0 -7
  177. data/lib/graphql/define/non_null_with_bang.rb +0 -16
  178. data/lib/graphql/define/type_definer.rb +0 -31
  179. data/lib/graphql/define.rb +0 -31
  180. data/lib/graphql/deprecated_dsl.rb +0 -55
  181. data/lib/graphql/directive/deprecated_directive.rb +0 -2
  182. data/lib/graphql/directive/include_directive.rb +0 -2
  183. data/lib/graphql/directive/skip_directive.rb +0 -2
  184. data/lib/graphql/directive.rb +0 -107
  185. data/lib/graphql/enum_type.rb +0 -133
  186. data/lib/graphql/execution/execute.rb +0 -333
  187. data/lib/graphql/execution/flatten.rb +0 -40
  188. data/lib/graphql/execution/instrumentation.rb +0 -92
  189. data/lib/graphql/execution/lazy/resolve.rb +0 -91
  190. data/lib/graphql/execution/typecast.rb +0 -50
  191. data/lib/graphql/field/resolve.rb +0 -59
  192. data/lib/graphql/field.rb +0 -226
  193. data/lib/graphql/float_type.rb +0 -2
  194. data/lib/graphql/function.rb +0 -128
  195. data/lib/graphql/id_type.rb +0 -2
  196. data/lib/graphql/input_object_type.rb +0 -138
  197. data/lib/graphql/int_type.rb +0 -2
  198. data/lib/graphql/interface_type.rb +0 -72
  199. data/lib/graphql/internal_representation/document.rb +0 -27
  200. data/lib/graphql/internal_representation/node.rb +0 -206
  201. data/lib/graphql/internal_representation/print.rb +0 -51
  202. data/lib/graphql/internal_representation/rewrite.rb +0 -184
  203. data/lib/graphql/internal_representation/scope.rb +0 -88
  204. data/lib/graphql/internal_representation/visit.rb +0 -36
  205. data/lib/graphql/internal_representation.rb +0 -7
  206. data/lib/graphql/language/lexer.rl +0 -260
  207. data/lib/graphql/list_type.rb +0 -80
  208. data/lib/graphql/non_null_type.rb +0 -71
  209. data/lib/graphql/object_type.rb +0 -130
  210. data/lib/graphql/query/arguments.rb +0 -189
  211. data/lib/graphql/query/arguments_cache.rb +0 -24
  212. data/lib/graphql/query/executor.rb +0 -52
  213. data/lib/graphql/query/literal_input.rb +0 -136
  214. data/lib/graphql/query/serial_execution/field_resolution.rb +0 -92
  215. data/lib/graphql/query/serial_execution/operation_resolution.rb +0 -19
  216. data/lib/graphql/query/serial_execution/selection_resolution.rb +0 -23
  217. data/lib/graphql/query/serial_execution/value_resolution.rb +0 -87
  218. data/lib/graphql/query/serial_execution.rb +0 -40
  219. data/lib/graphql/relay/array_connection.rb +0 -83
  220. data/lib/graphql/relay/base_connection.rb +0 -189
  221. data/lib/graphql/relay/connection_instrumentation.rb +0 -54
  222. data/lib/graphql/relay/connection_resolve.rb +0 -43
  223. data/lib/graphql/relay/connection_type.rb +0 -54
  224. data/lib/graphql/relay/edge.rb +0 -27
  225. data/lib/graphql/relay/edge_type.rb +0 -19
  226. data/lib/graphql/relay/edges_instrumentation.rb +0 -39
  227. data/lib/graphql/relay/global_id_resolve.rb +0 -17
  228. data/lib/graphql/relay/mongo_relation_connection.rb +0 -50
  229. data/lib/graphql/relay/mutation/instrumentation.rb +0 -23
  230. data/lib/graphql/relay/mutation/resolve.rb +0 -56
  231. data/lib/graphql/relay/mutation/result.rb +0 -38
  232. data/lib/graphql/relay/mutation.rb +0 -106
  233. data/lib/graphql/relay/node.rb +0 -39
  234. data/lib/graphql/relay/page_info.rb +0 -7
  235. data/lib/graphql/relay/relation_connection.rb +0 -188
  236. data/lib/graphql/relay/type_extensions.rb +0 -32
  237. data/lib/graphql/scalar_type.rb +0 -91
  238. data/lib/graphql/schema/catchall_middleware.rb +0 -35
  239. data/lib/graphql/schema/default_parse_error.rb +0 -10
  240. data/lib/graphql/schema/default_type_error.rb +0 -17
  241. data/lib/graphql/schema/member/accepts_definition.rb +0 -164
  242. data/lib/graphql/schema/member/cached_graphql_definition.rb +0 -58
  243. data/lib/graphql/schema/member/instrumentation.rb +0 -131
  244. data/lib/graphql/schema/middleware_chain.rb +0 -82
  245. data/lib/graphql/schema/possible_types.rb +0 -44
  246. data/lib/graphql/schema/rescue_middleware.rb +0 -60
  247. data/lib/graphql/schema/timeout_middleware.rb +0 -88
  248. data/lib/graphql/schema/traversal.rb +0 -228
  249. data/lib/graphql/schema/validation.rb +0 -313
  250. data/lib/graphql/static_validation/default_visitor.rb +0 -15
  251. data/lib/graphql/static_validation/no_validate_visitor.rb +0 -10
  252. data/lib/graphql/string_type.rb +0 -2
  253. data/lib/graphql/subscriptions/subscription_root.rb +0 -76
  254. data/lib/graphql/tracing/skylight_tracing.rb +0 -70
  255. data/lib/graphql/types/relay/default_relay.rb +0 -31
  256. data/lib/graphql/types/relay/node_field.rb +0 -24
  257. data/lib/graphql/types/relay/nodes_field.rb +0 -43
  258. data/lib/graphql/union_type.rb +0 -115
  259. data/lib/graphql/upgrader/member.rb +0 -937
  260. data/lib/graphql/upgrader/schema.rb +0 -38
@@ -20,6 +20,15 @@ module GraphQL
20
20
  @graphql_metadata = nil
21
21
  end
22
22
 
23
+ def path
24
+ @path ||= build_path([])
25
+ end
26
+
27
+ def build_path(path_array)
28
+ graphql_result_name && path_array.unshift(graphql_result_name)
29
+ @graphql_parent ? @graphql_parent.build_path(path_array) : path_array
30
+ end
31
+
23
32
  attr_accessor :graphql_dead
24
33
  attr_reader :graphql_parent, :graphql_result_name
25
34
 
@@ -148,13 +157,24 @@ module GraphQL
148
157
  # @return [GraphQL::Query::Context]
149
158
  attr_reader :context
150
159
 
151
- def initialize(query:)
160
+ def thread_info
161
+ info = Thread.current[:__graphql_runtime_info]
162
+ if !info
163
+ new_ti = {}
164
+ info = Thread.current[:__graphql_runtime_info] = new_ti
165
+ end
166
+ info
167
+ end
168
+
169
+ def initialize(query:, lazies_at_depth:)
152
170
  @query = query
153
171
  @dataloader = query.multiplex.dataloader
172
+ @lazies_at_depth = lazies_at_depth
154
173
  @schema = query.schema
155
174
  @context = query.context
156
175
  @multiplex_context = query.multiplex.context
157
- @interpreter_context = @context.namespace(:interpreter)
176
+ # Start this off empty:
177
+ Thread.current[:__graphql_runtime_info] = nil
158
178
  @response = GraphQLResultHash.new(nil, nil)
159
179
  # Identify runtime directives by checking which of this schema's directives have overridden `def self.resolve`
160
180
  @runtime_directive_names = []
@@ -198,8 +218,7 @@ module GraphQL
198
218
  root_operation = query.selected_operation
199
219
  root_op_type = root_operation.operation_type || "query"
200
220
  root_type = schema.root_type_for_operation(root_op_type)
201
- path = []
202
- set_all_interpreter_context(query.root_value, nil, nil, path)
221
+ set_all_interpreter_context(query.root_value, nil, nil, nil, @response)
203
222
  object_proxy = authorized_new(root_type, query.root_value, context)
204
223
  object_proxy = schema.sync_lazy(object_proxy)
205
224
 
@@ -226,11 +245,9 @@ module GraphQL
226
245
  end
227
246
 
228
247
  @dataloader.append_job {
229
- set_all_interpreter_context(query.root_value, nil, nil, path)
248
+ set_all_interpreter_context(query.root_value, nil, nil, nil, selection_response)
230
249
  call_method_on_directives(:resolve, object_proxy, selections.graphql_directives) do
231
250
  evaluate_selections(
232
- path,
233
- context.scoped_context,
234
251
  object_proxy,
235
252
  root_type,
236
253
  root_op_type == "mutation",
@@ -244,10 +261,7 @@ module GraphQL
244
261
  end
245
262
  end
246
263
  end
247
- delete_interpreter_context(:current_path)
248
- delete_interpreter_context(:current_field)
249
- delete_interpreter_context(:current_object)
250
- delete_interpreter_context(:current_arguments)
264
+ delete_all_interpreter_context
251
265
  nil
252
266
  end
253
267
 
@@ -349,15 +363,15 @@ module GraphQL
349
363
  NO_ARGS = {}.freeze
350
364
 
351
365
  # @return [void]
352
- def evaluate_selections(path, scoped_context, owner_object, owner_type, is_eager_selection, gathered_selections, selections_result, target_result, parent_object) # rubocop:disable Metrics/ParameterLists
353
- set_all_interpreter_context(owner_object, nil, nil, path)
366
+ def evaluate_selections(owner_object, owner_type, is_eager_selection, gathered_selections, selections_result, target_result, parent_object) # rubocop:disable Metrics/ParameterLists
367
+ set_all_interpreter_context(owner_object, nil, nil, nil, selections_result)
354
368
 
355
369
  finished_jobs = 0
356
370
  enqueued_jobs = gathered_selections.size
357
371
  gathered_selections.each do |result_name, field_ast_nodes_or_ast_node|
358
372
  @dataloader.append_job {
359
373
  evaluate_selection(
360
- path, result_name, field_ast_nodes_or_ast_node, scoped_context, owner_object, owner_type, is_eager_selection, selections_result, parent_object
374
+ result_name, field_ast_nodes_or_ast_node, owner_object, owner_type, is_eager_selection, selections_result, parent_object
361
375
  )
362
376
  finished_jobs += 1
363
377
  if target_result && finished_jobs == enqueued_jobs
@@ -369,10 +383,8 @@ module GraphQL
369
383
  selections_result
370
384
  end
371
385
 
372
- attr_reader :progress_path
373
-
374
386
  # @return [void]
375
- def evaluate_selection(path, result_name, field_ast_nodes_or_ast_node, scoped_context, owner_object, owner_type, is_eager_field, selections_result, parent_object) # rubocop:disable Metrics/ParameterLists
387
+ def evaluate_selection(result_name, field_ast_nodes_or_ast_node, owner_object, owner_type, is_eager_field, selections_result, parent_object) # rubocop:disable Metrics/ParameterLists
376
388
  return if dead_result?(selections_result)
377
389
  # As a performance optimization, the hash key will be a `Node` if
378
390
  # there's only one selection of the field. But if there are multiple
@@ -400,11 +412,8 @@ module GraphQL
400
412
  raise "Invariant: no field for #{owner_type}.#{field_name}"
401
413
  end
402
414
  end
403
- return_type = field_defn.type
404
415
 
405
- next_path = path.dup
406
- next_path << result_name
407
- next_path.freeze
416
+ return_type = field_defn.type
408
417
 
409
418
  # This seems janky, but we need to know
410
419
  # the field's return type at this path in order
@@ -413,9 +422,7 @@ module GraphQL
413
422
  (selections_result.graphql_non_null_field_names ||= []).push(result_name)
414
423
  end
415
424
  # Set this before calling `run_with_directives`, so that the directive can have the latest path
416
- set_all_interpreter_context(nil, field_defn, nil, next_path)
417
-
418
- context.scoped_context = scoped_context
425
+ set_all_interpreter_context(nil, field_defn, nil, result_name, selections_result)
419
426
  object = owner_object
420
427
 
421
428
  if is_introspection
@@ -425,21 +432,19 @@ module GraphQL
425
432
  total_args_count = field_defn.arguments(context).size
426
433
  if total_args_count == 0
427
434
  resolved_arguments = GraphQL::Execution::Interpreter::Arguments::EMPTY
428
- evaluate_selection_with_args(resolved_arguments, field_defn, next_path, ast_node, field_ast_nodes, scoped_context, owner_type, object, is_eager_field, result_name, selections_result, parent_object)
435
+ evaluate_selection_with_args(resolved_arguments, field_defn, ast_node, field_ast_nodes, owner_type, object, is_eager_field, result_name, selections_result, parent_object, return_type)
429
436
  else
430
437
  # TODO remove all arguments(...) usages?
431
438
  @query.arguments_cache.dataload_for(ast_node, field_defn, object) do |resolved_arguments|
432
- evaluate_selection_with_args(resolved_arguments, field_defn, next_path, ast_node, field_ast_nodes, scoped_context, owner_type, object, is_eager_field, result_name, selections_result, parent_object)
439
+ evaluate_selection_with_args(resolved_arguments, field_defn, ast_node, field_ast_nodes, owner_type, object, is_eager_field, result_name, selections_result, parent_object, return_type)
433
440
  end
434
441
  end
435
442
  end
436
443
 
437
- def evaluate_selection_with_args(arguments, field_defn, next_path, ast_node, field_ast_nodes, scoped_context, owner_type, object, is_eager_field, result_name, selection_result, parent_object) # rubocop:disable Metrics/ParameterLists
438
- context.scoped_context = scoped_context
439
- return_type = field_defn.type
440
- after_lazy(arguments, owner: owner_type, field: field_defn, path: next_path, ast_node: ast_node, scoped_context: context.scoped_context, owner_object: object, arguments: arguments, result_name: result_name, result: selection_result) do |resolved_arguments|
444
+ 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) # rubocop:disable Metrics/ParameterLists
445
+ after_lazy(arguments, owner: owner_type, field: field_defn, ast_node: ast_node, owner_object: object, arguments: arguments, result_name: result_name, result: selection_result) do |resolved_arguments|
441
446
  if resolved_arguments.is_a?(GraphQL::ExecutionError) || resolved_arguments.is_a?(GraphQL::UnauthorizedError)
442
- continue_value(next_path, resolved_arguments, owner_type, field_defn, return_type.non_null?, ast_node, result_name, selection_result)
447
+ continue_value(resolved_arguments, owner_type, field_defn, return_type.non_null?, ast_node, result_name, selection_result)
443
448
  next
444
449
  end
445
450
 
@@ -455,9 +460,9 @@ module GraphQL
455
460
  when :ast_node
456
461
  extra_args[:ast_node] = ast_node
457
462
  when :execution_errors
458
- extra_args[:execution_errors] = ExecutionErrors.new(context, ast_node, next_path)
463
+ extra_args[:execution_errors] = ExecutionErrors.new(context, ast_node, current_path)
459
464
  when :path
460
- extra_args[:path] = next_path
465
+ extra_args[:path] = current_path
461
466
  when :lookahead
462
467
  if !field_ast_nodes
463
468
  field_ast_nodes = [ast_node]
@@ -472,10 +477,6 @@ module GraphQL
472
477
  # Use this flag to tell Interpreter::Arguments to add itself
473
478
  # to the keyword args hash _before_ freezing everything.
474
479
  extra_args[:argument_details] = :__arguments_add_self
475
- when :irep_node
476
- # This is used by `__typename` in order to support the legacy runtime,
477
- # but it has no use here (and it's always `nil`).
478
- # Stop adding it here to avoid the overhead of `.merge_extras` below.
479
480
  when :parent
480
481
  extra_args[:parent] = parent_object
481
482
  else
@@ -488,7 +489,7 @@ module GraphQL
488
489
  resolved_arguments.keyword_arguments
489
490
  end
490
491
 
491
- set_all_interpreter_context(nil, nil, resolved_arguments, nil)
492
+ set_all_interpreter_context(nil, nil, resolved_arguments, result_name, selection_result)
492
493
 
493
494
  # Optimize for the case that field is selected only once
494
495
  if field_ast_nodes.nil? || field_ast_nodes.size == 1
@@ -506,18 +507,22 @@ module GraphQL
506
507
  field_result = call_method_on_directives(:resolve, object, directives) do
507
508
  # Actually call the field resolver and capture the result
508
509
  app_result = begin
509
- query.with_error_handling do
510
- query.trace("execute_field", {owner: owner_type, field: field_defn, path: next_path, ast_node: ast_node, query: query, object: object, arguments: kwarg_arguments}) do
511
- field_defn.resolve(object, kwarg_arguments, context)
512
- end
510
+ query.current_trace.execute_field(field: field_defn, ast_node: ast_node, query: query, object: object, arguments: kwarg_arguments) do
511
+ field_defn.resolve(object, kwarg_arguments, context)
513
512
  end
514
513
  rescue GraphQL::ExecutionError => err
515
514
  err
515
+ rescue StandardError => err
516
+ begin
517
+ query.handle_or_reraise(err)
518
+ rescue GraphQL::ExecutionError => ex_err
519
+ ex_err
520
+ end
516
521
  end
517
- after_lazy(app_result, owner: owner_type, field: field_defn, path: next_path, ast_node: ast_node, scoped_context: context.scoped_context, owner_object: object, arguments: resolved_arguments, result_name: result_name, result: selection_result) do |inner_result|
518
- continue_value = continue_value(next_path, inner_result, owner_type, field_defn, return_type.non_null?, ast_node, result_name, selection_result)
522
+ after_lazy(app_result, owner: owner_type, field: field_defn, ast_node: ast_node, owner_object: object, arguments: resolved_arguments, result_name: result_name, result: selection_result) do |inner_result|
523
+ continue_value = continue_value(inner_result, owner_type, field_defn, return_type.non_null?, ast_node, result_name, selection_result)
519
524
  if HALT != continue_value
520
- continue_field(next_path, continue_value, owner_type, field_defn, return_type, ast_node, next_selections, false, object, resolved_arguments, result_name, selection_result)
525
+ continue_field(continue_value, owner_type, field_defn, return_type, ast_node, next_selections, false, object, resolved_arguments, result_name, selection_result)
521
526
  end
522
527
  end
523
528
  end
@@ -582,8 +587,20 @@ module GraphQL
582
587
  end
583
588
  end
584
589
 
590
+ def current_path
591
+ ti = thread_info
592
+ path = ti &&
593
+ (result = ti[:current_result]) &&
594
+ (result.path)
595
+ if path && (rn = ti[:current_result_name])
596
+ path = path.dup
597
+ path.push(rn)
598
+ end
599
+ path
600
+ end
601
+
585
602
  HALT = Object.new
586
- def continue_value(path, value, parent_type, field, is_non_null, ast_node, result_name, selection_result) # rubocop:disable Metrics/ParameterLists
603
+ def continue_value(value, parent_type, field, is_non_null, ast_node, result_name, selection_result) # rubocop:disable Metrics/ParameterLists
587
604
  case value
588
605
  when nil
589
606
  if is_non_null
@@ -602,7 +619,7 @@ module GraphQL
602
619
  # every time.
603
620
  if value.is_a?(GraphQL::ExecutionError)
604
621
  if selection_result.nil? || !dead_result?(selection_result)
605
- value.path ||= path
622
+ value.path ||= current_path
606
623
  value.ast_node ||= ast_node
607
624
  context.errors << value
608
625
  if selection_result
@@ -610,6 +627,16 @@ module GraphQL
610
627
  end
611
628
  end
612
629
  HALT
630
+ elsif value.is_a?(GraphQL::UnauthorizedFieldError)
631
+ value.field ||= field
632
+ # this hook might raise & crash, or it might return
633
+ # a replacement value
634
+ next_value = begin
635
+ schema.unauthorized_field(value)
636
+ rescue GraphQL::ExecutionError => err
637
+ err
638
+ end
639
+ continue_value(next_value, parent_type, field, is_non_null, ast_node, result_name, selection_result)
613
640
  elsif value.is_a?(GraphQL::UnauthorizedError)
614
641
  # this hook might raise & crash, or it might return
615
642
  # a replacement value
@@ -618,8 +645,8 @@ module GraphQL
618
645
  rescue GraphQL::ExecutionError => err
619
646
  err
620
647
  end
621
- continue_value(path, next_value, parent_type, field, is_non_null, ast_node, result_name, selection_result)
622
- elsif GraphQL::Execution::Execute::SKIP == value
648
+ continue_value(next_value, parent_type, field, is_non_null, ast_node, result_name, selection_result)
649
+ elsif GraphQL::Execution::SKIP == value
623
650
  # It's possible a lazy was already written here
624
651
  case selection_result
625
652
  when GraphQLResultHash
@@ -644,7 +671,7 @@ module GraphQL
644
671
  if selection_result.nil? || !dead_result?(selection_result)
645
672
  value.each_with_index do |error, index|
646
673
  error.ast_node ||= ast_node
647
- error.path ||= path + (list_type_at_all ? [index] : [])
674
+ error.path ||= current_path + (list_type_at_all ? [index] : [])
648
675
  context.errors << error
649
676
  end
650
677
  if selection_result
@@ -677,7 +704,7 @@ module GraphQL
677
704
  # Location information from `path` and `ast_node`.
678
705
  #
679
706
  # @return [Lazy, Array, Hash, Object] Lazy, Array, and Hash are all traversed to resolve lazy values later
680
- def continue_field(path, value, owner_type, field, current_type, ast_node, next_selections, is_non_null, owner_object, arguments, result_name, selection_result) # rubocop:disable Metrics/ParameterLists
707
+ def continue_field(value, owner_type, field, current_type, ast_node, next_selections, is_non_null, owner_object, arguments, result_name, selection_result) # rubocop:disable Metrics/ParameterLists
681
708
  if current_type.non_null?
682
709
  current_type = current_type.of_type
683
710
  is_non_null = true
@@ -685,16 +712,24 @@ module GraphQL
685
712
 
686
713
  case current_type.kind.name
687
714
  when "SCALAR", "ENUM"
688
- r = current_type.coerce_result(value, context)
715
+ r = begin
716
+ current_type.coerce_result(value, context)
717
+ rescue StandardError => err
718
+ schema.handle_or_reraise(context, err)
719
+ end
689
720
  set_result(selection_result, result_name, r)
690
721
  r
691
722
  when "UNION", "INTERFACE"
692
- resolved_type_or_lazy, resolved_value = resolve_type(current_type, value, path)
693
- resolved_value ||= value
723
+ resolved_type_or_lazy = resolve_type(current_type, value)
724
+ after_lazy(resolved_type_or_lazy, owner: current_type, ast_node: ast_node, field: field, owner_object: owner_object, arguments: arguments, trace: false, result_name: result_name, result: selection_result) do |resolved_type_result|
725
+ if resolved_type_result.is_a?(Array) && resolved_type_result.length == 2
726
+ resolved_type, resolved_value = resolved_type_result
727
+ else
728
+ resolved_type = resolved_type_result
729
+ resolved_value = value
730
+ end
694
731
 
695
- after_lazy(resolved_type_or_lazy, owner: current_type, path: path, ast_node: ast_node, scoped_context: context.scoped_context, field: field, owner_object: owner_object, arguments: arguments, trace: false, result_name: result_name, result: selection_result) do |resolved_type|
696
732
  possible_types = query.possible_types(current_type)
697
-
698
733
  if !possible_types.include?(resolved_type)
699
734
  parent_type = field.owner_type
700
735
  err_class = current_type::UnresolvedTypeError
@@ -703,7 +738,7 @@ module GraphQL
703
738
  set_result(selection_result, result_name, nil)
704
739
  nil
705
740
  else
706
- continue_field(path, resolved_value, owner_type, field, resolved_type, ast_node, next_selections, is_non_null, owner_object, arguments, result_name, selection_result)
741
+ continue_field(resolved_value, owner_type, field, resolved_type, ast_node, next_selections, is_non_null, owner_object, arguments, result_name, selection_result)
707
742
  end
708
743
  end
709
744
  when "OBJECT"
@@ -712,8 +747,8 @@ module GraphQL
712
747
  rescue GraphQL::ExecutionError => err
713
748
  err
714
749
  end
715
- after_lazy(object_proxy, owner: current_type, path: path, ast_node: ast_node, scoped_context: context.scoped_context, field: field, owner_object: owner_object, arguments: arguments, trace: false, result_name: result_name, result: selection_result) do |inner_object|
716
- continue_value = continue_value(path, inner_object, owner_type, field, is_non_null, ast_node, result_name, selection_result)
750
+ after_lazy(object_proxy, owner: current_type, ast_node: ast_node, field: field, owner_object: owner_object, arguments: arguments, trace: false, result_name: result_name, result: selection_result) do |inner_object|
751
+ continue_value = continue_value(inner_object, owner_type, field, is_non_null, ast_node, result_name, selection_result)
717
752
  if HALT != continue_value
718
753
  response_hash = GraphQLResultHash.new(result_name, selection_result)
719
754
  set_result(selection_result, result_name, response_hash)
@@ -734,11 +769,10 @@ module GraphQL
734
769
  this_result = response_hash
735
770
  final_result = nil
736
771
  end
737
- set_all_interpreter_context(continue_value, nil, nil, path) # reset this mutable state
772
+ # Don't pass `result_name` here because it's already included in the new response hash
773
+ set_all_interpreter_context(continue_value, nil, nil, nil, this_result) # reset this mutable state
738
774
  call_method_on_directives(:resolve, continue_value, selections.graphql_directives) do
739
775
  evaluate_selections(
740
- path,
741
- context.scoped_context,
742
776
  continue_value,
743
777
  current_type,
744
778
  false,
@@ -759,50 +793,55 @@ module GraphQL
759
793
  response_list = GraphQLResultArray.new(result_name, selection_result)
760
794
  response_list.graphql_non_null_list_items = inner_type.non_null?
761
795
  set_result(selection_result, result_name, response_list)
762
-
763
796
  idx = 0
764
- scoped_context = context.scoped_context
765
- begin
797
+ list_value = begin
766
798
  value.each do |inner_value|
767
799
  break if dead_result?(response_list)
768
- next_path = path.dup
769
- next_path << idx
770
800
  this_idx = idx
771
- next_path.freeze
772
801
  idx += 1
773
802
  if use_dataloader_job
774
803
  @dataloader.append_job do
775
- resolve_list_item(inner_value, inner_type, next_path, ast_node, scoped_context, field, owner_object, arguments, this_idx, response_list, next_selections, owner_type)
804
+ resolve_list_item(inner_value, inner_type, ast_node, field, owner_object, arguments, this_idx, response_list, next_selections, owner_type)
776
805
  end
777
806
  else
778
- resolve_list_item(inner_value, inner_type, next_path, ast_node, scoped_context, field, owner_object, arguments, this_idx, response_list, next_selections, owner_type)
807
+ resolve_list_item(inner_value, inner_type, ast_node, field, owner_object, arguments, this_idx, response_list, next_selections, owner_type)
779
808
  end
780
809
  end
810
+
811
+ response_list
781
812
  rescue NoMethodError => err
782
813
  # Ruby 2.2 doesn't have NoMethodError#receiver, can't check that one in this case. (It's been EOL since 2017.)
783
814
  if err.name == :each && (err.respond_to?(:receiver) ? err.receiver == value : true)
784
815
  # This happens when the GraphQL schema doesn't match the implementation. Help the dev debug.
785
- raise ListResultFailedError.new(value: value, field: field, path: path)
816
+ raise ListResultFailedError.new(value: value, field: field, path: current_path)
786
817
  else
787
818
  # This was some other NoMethodError -- let it bubble to reveal the real error.
788
819
  raise
789
820
  end
821
+ rescue GraphQL::ExecutionError, GraphQL::UnauthorizedError => ex_err
822
+ ex_err
823
+ rescue StandardError => err
824
+ begin
825
+ query.handle_or_reraise(err)
826
+ rescue GraphQL::ExecutionError => ex_err
827
+ ex_err
828
+ end
790
829
  end
791
830
 
792
- response_list
831
+ continue_value(list_value, owner_type, field, inner_type.non_null?, ast_node, result_name, selection_result)
793
832
  else
794
833
  raise "Invariant: Unhandled type kind #{current_type.kind} (#{current_type})"
795
834
  end
796
835
  end
797
836
 
798
- def resolve_list_item(inner_value, inner_type, next_path, ast_node, scoped_context, field, owner_object, arguments, this_idx, response_list, next_selections, owner_type) # rubocop:disable Metrics/ParameterLists
799
- set_all_interpreter_context(nil, nil, nil, next_path)
837
+ def resolve_list_item(inner_value, inner_type, ast_node, field, owner_object, arguments, this_idx, response_list, next_selections, owner_type) # rubocop:disable Metrics/ParameterLists
838
+ set_all_interpreter_context(nil, nil, nil, this_idx, response_list)
800
839
  call_method_on_directives(:resolve_each, owner_object, ast_node.directives) do
801
840
  # This will update `response_list` with the lazy
802
- after_lazy(inner_value, owner: inner_type, path: next_path, ast_node: ast_node, scoped_context: scoped_context, field: field, owner_object: owner_object, arguments: arguments, result_name: this_idx, result: response_list) do |inner_inner_value|
803
- continue_value = continue_value(next_path, inner_inner_value, owner_type, field, inner_type.non_null?, ast_node, this_idx, response_list)
841
+ after_lazy(inner_value, owner: inner_type, ast_node: ast_node, field: field, owner_object: owner_object, arguments: arguments, result_name: this_idx, result: response_list) do |inner_inner_value|
842
+ continue_value = continue_value(inner_inner_value, owner_type, field, inner_type.non_null?, ast_node, this_idx, response_list)
804
843
  if HALT != continue_value
805
- continue_field(next_path, continue_value, owner_type, field, inner_type, ast_node, next_selections, false, owner_object, arguments, this_idx, response_list)
844
+ continue_field(continue_value, owner_type, field, inner_type, ast_node, next_selections, false, owner_object, arguments, this_idx, response_list)
806
845
  end
807
846
  end
808
847
  end
@@ -819,12 +858,8 @@ module GraphQL
819
858
  yield
820
859
  else
821
860
  dir_defn = @schema_directives.fetch(dir_node.name)
822
- if !dir_defn.is_a?(Class)
823
- dir_defn = dir_defn.type_class || raise("Only class-based directives are supported (not `@#{dir_node.name}`)")
824
- end
825
861
  raw_dir_args = arguments(nil, dir_defn, dir_node)
826
862
  dir_args = continue_value(
827
- @context[:current_path], # path
828
863
  raw_dir_args, # value
829
864
  dir_defn, # parent_type
830
865
  nil, # field
@@ -847,7 +882,7 @@ module GraphQL
847
882
  # Check {Schema::Directive.include?} for each directive that's present
848
883
  def directives_include?(node, graphql_object, parent_type)
849
884
  node.directives.each do |dir_node|
850
- dir_defn = @schema_directives.fetch(dir_node.name).type_class || raise("Only class-based directives are supported (not #{dir_node.name.inspect})")
885
+ dir_defn = @schema_directives.fetch(dir_node.name)
851
886
  args = arguments(graphql_object, dir_defn, dir_node)
852
887
  if !dir_defn.include?(graphql_object, args, context)
853
888
  return false
@@ -856,50 +891,51 @@ module GraphQL
856
891
  true
857
892
  end
858
893
 
859
- def set_all_interpreter_context(object, field, arguments, path)
894
+ def set_all_interpreter_context(object, field, arguments, result_name, result)
895
+ ti = thread_info
860
896
  if object
861
- @context[:current_object] = @interpreter_context[:current_object] = object
897
+ ti[:current_object] = object
862
898
  end
863
899
  if field
864
- @context[:current_field] = @interpreter_context[:current_field] = field
900
+ ti[:current_field] = field
865
901
  end
866
902
  if arguments
867
- @context[:current_arguments] = @interpreter_context[:current_arguments] = arguments
903
+ ti[:current_arguments] = arguments
868
904
  end
869
- if path
870
- @context[:current_path] = @interpreter_context[:current_path] = path
905
+ ti[:current_result_name] = result_name
906
+ if result
907
+ ti[:current_result] = result
871
908
  end
872
909
  end
873
910
 
874
911
  # @param obj [Object] Some user-returned value that may want to be batched
875
- # @param path [Array<String>]
876
912
  # @param field [GraphQL::Schema::Field]
877
913
  # @param eager [Boolean] Set to `true` for mutation root fields only
878
914
  # @param trace [Boolean] If `false`, don't wrap this with field tracing
879
915
  # @return [GraphQL::Execution::Lazy, Object] If loading `object` will be deferred, it's a wrapper over it.
880
- def after_lazy(lazy_obj, owner:, field:, path:, scoped_context:, owner_object:, arguments:, ast_node:, result:, result_name:, eager: false, trace: true, &block)
916
+ def after_lazy(lazy_obj, owner:, field:, owner_object:, arguments:, ast_node:, result:, result_name:, eager: false, trace: true, &block)
881
917
  if lazy?(lazy_obj)
882
- lazy = GraphQL::Execution::Lazy.new(path: path, field: field) do
883
- set_all_interpreter_context(owner_object, field, arguments, path)
884
- context.scoped_context = scoped_context
918
+ orig_result = result
919
+ lazy = GraphQL::Execution::Lazy.new(field: field) do
920
+ set_all_interpreter_context(owner_object, field, arguments, result_name, orig_result)
885
921
  # Wrap the execution of _this_ method with tracing,
886
922
  # but don't wrap the continuation below
887
923
  inner_obj = begin
888
- query.with_error_handling do
889
- begin
890
- if trace
891
- query.trace("execute_field_lazy", {owner: owner, field: field, path: path, query: query, object: owner_object, arguments: arguments, ast_node: ast_node}) do
892
- schema.sync_lazy(lazy_obj)
893
- end
894
- else
895
- schema.sync_lazy(lazy_obj)
896
- end
897
- rescue GraphQL::ExecutionError, GraphQL::UnauthorizedError => err
898
- err
924
+ if trace
925
+ query.current_trace.execute_field_lazy(field: field, query: query, object: owner_object, arguments: arguments, ast_node: ast_node) do
926
+ schema.sync_lazy(lazy_obj)
899
927
  end
928
+ else
929
+ schema.sync_lazy(lazy_obj)
900
930
  end
901
- rescue GraphQL::ExecutionError => ex_err
931
+ rescue GraphQL::ExecutionError, GraphQL::UnauthorizedError => ex_err
902
932
  ex_err
933
+ rescue StandardError => err
934
+ begin
935
+ query.handle_or_reraise(err)
936
+ rescue GraphQL::ExecutionError => ex_err
937
+ ex_err
938
+ end
903
939
  end
904
940
  yield(inner_obj)
905
941
  end
@@ -908,10 +944,16 @@ module GraphQL
908
944
  lazy.value
909
945
  else
910
946
  set_result(result, result_name, lazy)
947
+ current_depth = 0
948
+ while result
949
+ current_depth += 1
950
+ result = result.graphql_parent
951
+ end
952
+ @lazies_at_depth[current_depth] << lazy
911
953
  lazy
912
954
  end
913
955
  else
914
- set_all_interpreter_context(owner_object, field, arguments, path)
956
+ set_all_interpreter_context(owner_object, field, arguments, result_name, result)
915
957
  yield(lazy_obj)
916
958
  end
917
959
  end
@@ -925,27 +967,24 @@ module GraphQL
925
967
  end
926
968
  end
927
969
 
928
- # Set this pair in the Query context, but also in the interpeter namespace,
929
- # for compatibility.
930
- def set_interpreter_context(key, value)
931
- @interpreter_context[key] = value
932
- @context[key] = value
933
- end
934
-
935
- def delete_interpreter_context(key)
936
- @interpreter_context.delete(key)
937
- @context.delete(key)
970
+ def delete_all_interpreter_context
971
+ if (ti = thread_info)
972
+ ti.delete(:current_result)
973
+ ti.delete(:current_result_name)
974
+ ti.delete(:current_field)
975
+ ti.delete(:current_object)
976
+ ti.delete(:current_arguments)
977
+ end
938
978
  end
939
979
 
940
- def resolve_type(type, value, path)
941
- trace_payload = { context: context, type: type, object: value, path: path }
942
- resolved_type, resolved_value = query.trace("resolve_type", trace_payload) do
980
+ def resolve_type(type, value)
981
+ resolved_type, resolved_value = query.current_trace.resolve_type(query: query, type: type, object: value) do
943
982
  query.resolve_type(type, value)
944
983
  end
945
984
 
946
985
  if lazy?(resolved_type)
947
986
  GraphQL::Execution::Lazy.new do
948
- query.trace("resolve_type_lazy", trace_payload) do
987
+ query.current_trace.resolve_type_lazy(query: query, type: type, object: value) do
949
988
  schema.sync_lazy(resolved_type)
950
989
  end
951
990
  end