graphql 1.9.18 → 1.13.24

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.
Files changed (353) hide show
  1. checksums.yaml +4 -4
  2. data/lib/generators/graphql/core.rb +21 -10
  3. data/lib/generators/graphql/enum_generator.rb +4 -10
  4. data/lib/generators/graphql/field_extractor.rb +31 -0
  5. data/lib/generators/graphql/input_generator.rb +50 -0
  6. data/lib/generators/graphql/install/mutation_root_generator.rb +34 -0
  7. data/lib/generators/graphql/{templates → install/templates}/base_mutation.erb +2 -0
  8. data/lib/generators/graphql/{templates → install/templates}/mutation_type.erb +2 -0
  9. data/lib/generators/graphql/install_generator.rb +44 -7
  10. data/lib/generators/graphql/interface_generator.rb +7 -7
  11. data/lib/generators/graphql/loader_generator.rb +1 -0
  12. data/lib/generators/graphql/mutation_create_generator.rb +22 -0
  13. data/lib/generators/graphql/mutation_delete_generator.rb +22 -0
  14. data/lib/generators/graphql/mutation_generator.rb +6 -30
  15. data/lib/generators/graphql/mutation_update_generator.rb +22 -0
  16. data/lib/generators/graphql/object_generator.rb +28 -12
  17. data/lib/generators/graphql/orm_mutations_base.rb +40 -0
  18. data/lib/generators/graphql/relay.rb +63 -0
  19. data/lib/generators/graphql/relay_generator.rb +21 -0
  20. data/lib/generators/graphql/scalar_generator.rb +4 -2
  21. data/lib/generators/graphql/templates/base_argument.erb +2 -0
  22. data/lib/generators/graphql/templates/base_connection.erb +8 -0
  23. data/lib/generators/graphql/templates/base_edge.erb +8 -0
  24. data/lib/generators/graphql/templates/base_enum.erb +2 -0
  25. data/lib/generators/graphql/templates/base_field.erb +2 -0
  26. data/lib/generators/graphql/templates/base_input_object.erb +2 -0
  27. data/lib/generators/graphql/templates/base_interface.erb +2 -0
  28. data/lib/generators/graphql/templates/base_object.erb +2 -0
  29. data/lib/generators/graphql/templates/base_scalar.erb +2 -0
  30. data/lib/generators/graphql/templates/base_union.erb +2 -0
  31. data/lib/generators/graphql/templates/enum.erb +7 -1
  32. data/lib/generators/graphql/templates/graphql_controller.erb +16 -12
  33. data/lib/generators/graphql/templates/input.erb +9 -0
  34. data/lib/generators/graphql/templates/interface.erb +6 -2
  35. data/lib/generators/graphql/templates/loader.erb +2 -0
  36. data/lib/generators/graphql/templates/mutation.erb +3 -1
  37. data/lib/generators/graphql/templates/mutation_create.erb +20 -0
  38. data/lib/generators/graphql/templates/mutation_delete.erb +20 -0
  39. data/lib/generators/graphql/templates/mutation_update.erb +21 -0
  40. data/lib/generators/graphql/templates/node_type.erb +9 -0
  41. data/lib/generators/graphql/templates/object.erb +7 -3
  42. data/lib/generators/graphql/templates/query_type.erb +3 -3
  43. data/lib/generators/graphql/templates/scalar.erb +5 -1
  44. data/lib/generators/graphql/templates/schema.erb +22 -27
  45. data/lib/generators/graphql/templates/union.erb +6 -2
  46. data/lib/generators/graphql/type_generator.rb +47 -10
  47. data/lib/generators/graphql/union_generator.rb +5 -5
  48. data/lib/graphql/analysis/analyze_query.rb +7 -0
  49. data/lib/graphql/analysis/ast/field_usage.rb +29 -2
  50. data/lib/graphql/analysis/ast/query_complexity.rb +174 -67
  51. data/lib/graphql/analysis/ast/visitor.rb +16 -7
  52. data/lib/graphql/analysis/ast.rb +21 -11
  53. data/lib/graphql/argument.rb +8 -36
  54. data/lib/graphql/backtrace/inspect_result.rb +0 -1
  55. data/lib/graphql/backtrace/legacy_tracer.rb +56 -0
  56. data/lib/graphql/backtrace/table.rb +44 -5
  57. data/lib/graphql/backtrace/traced_error.rb +0 -1
  58. data/lib/graphql/backtrace/tracer.rb +40 -9
  59. data/lib/graphql/backtrace.rb +28 -19
  60. data/lib/graphql/backwards_compatibility.rb +2 -1
  61. data/lib/graphql/base_type.rb +10 -4
  62. data/lib/graphql/boolean_type.rb +1 -1
  63. data/lib/graphql/compatibility/execution_specification/specification_schema.rb +2 -2
  64. data/lib/graphql/compatibility/execution_specification.rb +1 -0
  65. data/lib/graphql/compatibility/lazy_execution_specification.rb +2 -0
  66. data/lib/graphql/compatibility/query_parser_specification/parse_error_specification.rb +5 -9
  67. data/lib/graphql/compatibility/query_parser_specification.rb +2 -0
  68. data/lib/graphql/compatibility/schema_parser_specification.rb +2 -0
  69. data/lib/graphql/dataloader/null_dataloader.rb +22 -0
  70. data/lib/graphql/dataloader/request.rb +19 -0
  71. data/lib/graphql/dataloader/request_all.rb +19 -0
  72. data/lib/graphql/dataloader/source.rb +155 -0
  73. data/lib/graphql/dataloader.rb +308 -0
  74. data/lib/graphql/date_encoding_error.rb +16 -0
  75. data/lib/graphql/define/assign_enum_value.rb +1 -1
  76. data/lib/graphql/define/assign_global_id_field.rb +2 -2
  77. data/lib/graphql/define/assign_object_field.rb +1 -1
  78. data/lib/graphql/define/defined_object_proxy.rb +5 -8
  79. data/lib/graphql/define/instance_definable.rb +60 -110
  80. data/lib/graphql/define/type_definer.rb +5 -5
  81. data/lib/graphql/deprecated_dsl.rb +18 -5
  82. data/lib/graphql/deprecation.rb +9 -0
  83. data/lib/graphql/directive/deprecated_directive.rb +1 -12
  84. data/lib/graphql/directive/include_directive.rb +1 -1
  85. data/lib/graphql/directive/skip_directive.rb +1 -1
  86. data/lib/graphql/directive.rb +9 -6
  87. data/lib/graphql/enum_type.rb +14 -74
  88. data/lib/graphql/execution/directive_checks.rb +2 -2
  89. data/lib/graphql/execution/errors.rb +110 -8
  90. data/lib/graphql/execution/execute.rb +8 -1
  91. data/lib/graphql/execution/instrumentation.rb +1 -1
  92. data/lib/graphql/execution/interpreter/argument_value.rb +28 -0
  93. data/lib/graphql/execution/interpreter/arguments.rb +88 -0
  94. data/lib/graphql/execution/interpreter/arguments_cache.rb +105 -0
  95. data/lib/graphql/execution/interpreter/handles_raw_value.rb +18 -0
  96. data/lib/graphql/execution/interpreter/resolve.rb +37 -25
  97. data/lib/graphql/execution/interpreter/runtime.rb +721 -386
  98. data/lib/graphql/execution/interpreter.rb +42 -19
  99. data/lib/graphql/execution/lazy/lazy_method_map.rb +4 -0
  100. data/lib/graphql/execution/lazy.rb +5 -1
  101. data/lib/graphql/execution/lookahead.rb +39 -114
  102. data/lib/graphql/execution/multiplex.rb +50 -25
  103. data/lib/graphql/field.rb +15 -119
  104. data/lib/graphql/filter.rb +1 -1
  105. data/lib/graphql/float_type.rb +1 -1
  106. data/lib/graphql/function.rb +5 -30
  107. data/lib/graphql/id_type.rb +1 -1
  108. data/lib/graphql/input_object_type.rb +9 -25
  109. data/lib/graphql/int_type.rb +1 -1
  110. data/lib/graphql/integer_decoding_error.rb +17 -0
  111. data/lib/graphql/integer_encoding_error.rb +18 -2
  112. data/lib/graphql/interface_type.rb +10 -24
  113. data/lib/graphql/internal_representation/document.rb +2 -2
  114. data/lib/graphql/internal_representation/rewrite.rb +1 -1
  115. data/lib/graphql/internal_representation/scope.rb +2 -2
  116. data/lib/graphql/internal_representation/visit.rb +2 -2
  117. data/lib/graphql/introspection/base_object.rb +2 -5
  118. data/lib/graphql/introspection/directive_location_enum.rb +2 -2
  119. data/lib/graphql/introspection/directive_type.rb +12 -6
  120. data/lib/graphql/introspection/entry_points.rb +9 -9
  121. data/lib/graphql/introspection/enum_value_type.rb +2 -2
  122. data/lib/graphql/introspection/field_type.rb +9 -5
  123. data/lib/graphql/introspection/input_value_type.rb +41 -11
  124. data/lib/graphql/introspection/introspection_query.rb +6 -92
  125. data/lib/graphql/introspection/schema_type.rb +12 -12
  126. data/lib/graphql/introspection/type_type.rb +27 -17
  127. data/lib/graphql/introspection.rb +99 -0
  128. data/lib/graphql/invalid_null_error.rb +18 -0
  129. data/lib/graphql/language/block_string.rb +20 -5
  130. data/lib/graphql/language/cache.rb +37 -0
  131. data/lib/graphql/language/definition_slice.rb +21 -10
  132. data/lib/graphql/language/document_from_schema_definition.rb +116 -63
  133. data/lib/graphql/language/lexer.rb +53 -27
  134. data/lib/graphql/language/lexer.rl +5 -3
  135. data/lib/graphql/language/nodes.rb +67 -93
  136. data/lib/graphql/language/parser.rb +929 -896
  137. data/lib/graphql/language/parser.y +125 -102
  138. data/lib/graphql/language/printer.rb +11 -2
  139. data/lib/graphql/language/sanitized_printer.rb +222 -0
  140. data/lib/graphql/language/token.rb +0 -4
  141. data/lib/graphql/language/visitor.rb +2 -2
  142. data/lib/graphql/language.rb +3 -1
  143. data/lib/graphql/name_validator.rb +2 -7
  144. data/lib/graphql/non_null_type.rb +0 -10
  145. data/lib/graphql/object_type.rb +47 -58
  146. data/lib/graphql/pagination/active_record_relation_connection.rb +85 -0
  147. data/lib/graphql/pagination/array_connection.rb +77 -0
  148. data/lib/graphql/pagination/connection.rb +226 -0
  149. data/lib/graphql/pagination/connections.rb +160 -0
  150. data/lib/graphql/pagination/mongoid_relation_connection.rb +25 -0
  151. data/lib/graphql/pagination/relation_connection.rb +226 -0
  152. data/lib/graphql/pagination/sequel_dataset_connection.rb +28 -0
  153. data/lib/graphql/pagination.rb +6 -0
  154. data/lib/graphql/parse_error.rb +0 -1
  155. data/lib/graphql/query/arguments.rb +6 -4
  156. data/lib/graphql/query/arguments_cache.rb +1 -2
  157. data/lib/graphql/query/context.rb +52 -7
  158. data/lib/graphql/query/executor.rb +0 -1
  159. data/lib/graphql/query/fingerprint.rb +26 -0
  160. data/lib/graphql/query/input_validation_result.rb +32 -6
  161. data/lib/graphql/query/literal_input.rb +31 -11
  162. data/lib/graphql/query/null_context.rb +24 -8
  163. data/lib/graphql/query/serial_execution/field_resolution.rb +1 -1
  164. data/lib/graphql/query/serial_execution.rb +1 -0
  165. data/lib/graphql/query/validation_pipeline.rb +6 -4
  166. data/lib/graphql/query/variable_validation_error.rb +3 -3
  167. data/lib/graphql/query/variables.rb +50 -10
  168. data/lib/graphql/query.rb +77 -18
  169. data/lib/graphql/railtie.rb +9 -1
  170. data/lib/graphql/rake_task/validate.rb +3 -0
  171. data/lib/graphql/rake_task.rb +12 -9
  172. data/lib/graphql/relay/array_connection.rb +10 -12
  173. data/lib/graphql/relay/base_connection.rb +30 -13
  174. data/lib/graphql/relay/connection_instrumentation.rb +4 -4
  175. data/lib/graphql/relay/connection_type.rb +18 -4
  176. data/lib/graphql/relay/edge_type.rb +1 -0
  177. data/lib/graphql/relay/edges_instrumentation.rb +1 -2
  178. data/lib/graphql/relay/global_id_resolve.rb +1 -2
  179. data/lib/graphql/relay/mutation.rb +3 -87
  180. data/lib/graphql/relay/node.rb +3 -0
  181. data/lib/graphql/relay/page_info.rb +1 -1
  182. data/lib/graphql/relay/range_add.rb +27 -9
  183. data/lib/graphql/relay/relation_connection.rb +8 -10
  184. data/lib/graphql/relay/type_extensions.rb +2 -0
  185. data/lib/graphql/rubocop/graphql/base_cop.rb +36 -0
  186. data/lib/graphql/rubocop/graphql/default_null_true.rb +43 -0
  187. data/lib/graphql/rubocop/graphql/default_required_true.rb +43 -0
  188. data/lib/graphql/rubocop.rb +4 -0
  189. data/lib/graphql/scalar_type.rb +18 -60
  190. data/lib/graphql/schema/addition.rb +247 -0
  191. data/lib/graphql/schema/argument.rb +274 -18
  192. data/lib/graphql/schema/base_64_encoder.rb +2 -0
  193. data/lib/graphql/schema/build_from_definition/resolve_map/default_resolve.rb +1 -1
  194. data/lib/graphql/schema/build_from_definition/resolve_map.rb +13 -5
  195. data/lib/graphql/schema/build_from_definition.rb +320 -219
  196. data/lib/graphql/schema/built_in_types.rb +5 -5
  197. data/lib/graphql/schema/default_type_error.rb +2 -0
  198. data/lib/graphql/schema/directive/deprecated.rb +18 -0
  199. data/lib/graphql/schema/directive/feature.rb +1 -1
  200. data/lib/graphql/schema/directive/flagged.rb +57 -0
  201. data/lib/graphql/schema/directive/include.rb +2 -2
  202. data/lib/graphql/schema/directive/skip.rb +2 -2
  203. data/lib/graphql/schema/directive/transform.rb +14 -2
  204. data/lib/graphql/schema/directive.rb +130 -6
  205. data/lib/graphql/schema/enum.rb +121 -12
  206. data/lib/graphql/schema/enum_value.rb +24 -7
  207. data/lib/graphql/schema/field/connection_extension.rb +46 -20
  208. data/lib/graphql/schema/field/scope_extension.rb +1 -1
  209. data/lib/graphql/schema/field.rb +465 -181
  210. data/lib/graphql/schema/field_extension.rb +89 -2
  211. data/lib/graphql/schema/find_inherited_value.rb +17 -1
  212. data/lib/graphql/schema/finder.rb +16 -14
  213. data/lib/graphql/schema/input_object.rb +172 -37
  214. data/lib/graphql/schema/interface.rb +39 -25
  215. data/lib/graphql/schema/introspection_system.rb +106 -38
  216. data/lib/graphql/schema/late_bound_type.rb +3 -2
  217. data/lib/graphql/schema/list.rb +65 -1
  218. data/lib/graphql/schema/loader.rb +145 -102
  219. data/lib/graphql/schema/member/accepts_definition.rb +15 -3
  220. data/lib/graphql/schema/member/base_dsl_methods.rb +34 -28
  221. data/lib/graphql/schema/member/build_type.rb +19 -8
  222. data/lib/graphql/schema/member/cached_graphql_definition.rb +34 -2
  223. data/lib/graphql/schema/member/has_arguments.rb +206 -13
  224. data/lib/graphql/schema/member/has_ast_node.rb +20 -0
  225. data/lib/graphql/schema/member/has_deprecation_reason.rb +25 -0
  226. data/lib/graphql/schema/member/has_directives.rb +98 -0
  227. data/lib/graphql/schema/member/has_fields.rb +97 -32
  228. data/lib/graphql/schema/member/has_interfaces.rb +100 -0
  229. data/lib/graphql/schema/member/has_unresolved_type_error.rb +15 -0
  230. data/lib/graphql/schema/member/has_validators.rb +31 -0
  231. data/lib/graphql/schema/member/instrumentation.rb +0 -1
  232. data/lib/graphql/schema/member/type_system_helpers.rb +3 -3
  233. data/lib/graphql/schema/member/validates_input.rb +33 -0
  234. data/lib/graphql/schema/member.rb +11 -0
  235. data/lib/graphql/schema/middleware_chain.rb +1 -1
  236. data/lib/graphql/schema/mutation.rb +4 -0
  237. data/lib/graphql/schema/non_null.rb +37 -1
  238. data/lib/graphql/schema/object.rb +51 -38
  239. data/lib/graphql/schema/possible_types.rb +9 -4
  240. data/lib/graphql/schema/printer.rb +16 -35
  241. data/lib/graphql/schema/relay_classic_mutation.rb +40 -4
  242. data/lib/graphql/schema/resolver/has_payload_type.rb +34 -4
  243. data/lib/graphql/schema/resolver.rb +133 -79
  244. data/lib/graphql/schema/scalar.rb +43 -3
  245. data/lib/graphql/schema/subscription.rb +57 -21
  246. data/lib/graphql/schema/timeout.rb +29 -15
  247. data/lib/graphql/schema/timeout_middleware.rb +3 -1
  248. data/lib/graphql/schema/traversal.rb +2 -2
  249. data/lib/graphql/schema/type_expression.rb +21 -13
  250. data/lib/graphql/schema/type_membership.rb +19 -5
  251. data/lib/graphql/schema/union.rb +44 -3
  252. data/lib/graphql/schema/unique_within_type.rb +1 -2
  253. data/lib/graphql/schema/validation.rb +14 -4
  254. data/lib/graphql/schema/validator/allow_blank_validator.rb +29 -0
  255. data/lib/graphql/schema/validator/allow_null_validator.rb +26 -0
  256. data/lib/graphql/schema/validator/exclusion_validator.rb +33 -0
  257. data/lib/graphql/schema/validator/format_validator.rb +48 -0
  258. data/lib/graphql/schema/validator/inclusion_validator.rb +35 -0
  259. data/lib/graphql/schema/validator/length_validator.rb +59 -0
  260. data/lib/graphql/schema/validator/numericality_validator.rb +82 -0
  261. data/lib/graphql/schema/validator/required_validator.rb +82 -0
  262. data/lib/graphql/schema/validator.rb +171 -0
  263. data/lib/graphql/schema/warden.rb +193 -34
  264. data/lib/graphql/schema.rb +882 -247
  265. data/lib/graphql/static_validation/all_rules.rb +2 -0
  266. data/lib/graphql/static_validation/base_visitor.rb +17 -10
  267. data/lib/graphql/static_validation/definition_dependencies.rb +0 -1
  268. data/lib/graphql/static_validation/error.rb +3 -1
  269. data/lib/graphql/static_validation/literal_validator.rb +51 -26
  270. data/lib/graphql/static_validation/rules/argument_literals_are_compatible.rb +45 -83
  271. data/lib/graphql/static_validation/rules/argument_literals_are_compatible_error.rb +22 -6
  272. data/lib/graphql/static_validation/rules/arguments_are_defined.rb +35 -26
  273. data/lib/graphql/static_validation/rules/arguments_are_defined_error.rb +4 -2
  274. data/lib/graphql/static_validation/rules/directives_are_defined.rb +1 -1
  275. data/lib/graphql/static_validation/rules/directives_are_in_valid_locations.rb +2 -2
  276. data/lib/graphql/static_validation/rules/fields_are_defined_on_type.rb +4 -4
  277. data/lib/graphql/static_validation/rules/fields_have_appropriate_selections.rb +5 -5
  278. data/lib/graphql/static_validation/rules/fields_will_merge.rb +94 -51
  279. data/lib/graphql/static_validation/rules/fields_will_merge_error.rb +25 -4
  280. data/lib/graphql/static_validation/rules/fragment_spreads_are_possible.rb +3 -3
  281. data/lib/graphql/static_validation/rules/fragments_are_finite.rb +2 -2
  282. data/lib/graphql/static_validation/rules/input_object_names_are_unique.rb +30 -0
  283. data/lib/graphql/static_validation/rules/input_object_names_are_unique_error.rb +30 -0
  284. data/lib/graphql/static_validation/rules/query_root_exists.rb +17 -0
  285. data/lib/graphql/static_validation/rules/query_root_exists_error.rb +26 -0
  286. data/lib/graphql/static_validation/rules/required_arguments_are_present.rb +4 -2
  287. data/lib/graphql/static_validation/rules/required_input_object_attributes_are_present.rb +9 -10
  288. data/lib/graphql/static_validation/rules/unique_directives_per_location.rb +1 -1
  289. data/lib/graphql/static_validation/rules/variable_default_values_are_correctly_typed.rb +12 -13
  290. data/lib/graphql/static_validation/rules/variable_usages_are_allowed.rb +19 -14
  291. data/lib/graphql/static_validation/rules/variables_are_input_types.rb +1 -1
  292. data/lib/graphql/static_validation/rules/variables_are_used_and_defined.rb +5 -3
  293. data/lib/graphql/static_validation/type_stack.rb +2 -2
  294. data/lib/graphql/static_validation/validation_context.rb +13 -3
  295. data/lib/graphql/static_validation/validation_timeout_error.rb +25 -0
  296. data/lib/graphql/static_validation/validator.rb +43 -9
  297. data/lib/graphql/static_validation.rb +1 -0
  298. data/lib/graphql/string_encoding_error.rb +13 -3
  299. data/lib/graphql/string_type.rb +1 -1
  300. data/lib/graphql/subscriptions/action_cable_subscriptions.rb +123 -22
  301. data/lib/graphql/subscriptions/broadcast_analyzer.rb +81 -0
  302. data/lib/graphql/subscriptions/default_subscription_resolve_extension.rb +21 -0
  303. data/lib/graphql/subscriptions/event.rb +84 -30
  304. data/lib/graphql/subscriptions/instrumentation.rb +10 -6
  305. data/lib/graphql/subscriptions/serialize.rb +53 -6
  306. data/lib/graphql/subscriptions/subscription_root.rb +15 -5
  307. data/lib/graphql/subscriptions.rb +117 -49
  308. data/lib/graphql/tracing/active_support_notifications_tracing.rb +8 -17
  309. data/lib/graphql/tracing/appoptics_tracing.rb +173 -0
  310. data/lib/graphql/tracing/appsignal_tracing.rb +23 -0
  311. data/lib/graphql/tracing/data_dog_tracing.rb +32 -15
  312. data/lib/graphql/tracing/new_relic_tracing.rb +9 -12
  313. data/lib/graphql/tracing/notifications_tracing.rb +59 -0
  314. data/lib/graphql/tracing/platform_tracing.rb +66 -10
  315. data/lib/graphql/tracing/prometheus_tracing/graphql_collector.rb +4 -1
  316. data/lib/graphql/tracing/prometheus_tracing.rb +8 -0
  317. data/lib/graphql/tracing/scout_tracing.rb +19 -0
  318. data/lib/graphql/tracing/skylight_tracing.rb +9 -1
  319. data/lib/graphql/tracing/statsd_tracing.rb +42 -0
  320. data/lib/graphql/tracing.rb +15 -35
  321. data/lib/graphql/types/big_int.rb +5 -1
  322. data/lib/graphql/types/int.rb +10 -3
  323. data/lib/graphql/types/iso_8601_date.rb +16 -8
  324. data/lib/graphql/types/iso_8601_date_time.rb +32 -10
  325. data/lib/graphql/types/relay/base_connection.rb +6 -88
  326. data/lib/graphql/types/relay/base_edge.rb +2 -34
  327. data/lib/graphql/types/relay/connection_behaviors.rb +174 -0
  328. data/lib/graphql/types/relay/default_relay.rb +31 -0
  329. data/lib/graphql/types/relay/edge_behaviors.rb +64 -0
  330. data/lib/graphql/types/relay/has_node_field.rb +41 -0
  331. data/lib/graphql/types/relay/has_nodes_field.rb +41 -0
  332. data/lib/graphql/types/relay/node.rb +2 -4
  333. data/lib/graphql/types/relay/node_behaviors.rb +15 -0
  334. data/lib/graphql/types/relay/node_field.rb +3 -22
  335. data/lib/graphql/types/relay/nodes_field.rb +16 -18
  336. data/lib/graphql/types/relay/page_info.rb +2 -14
  337. data/lib/graphql/types/relay/page_info_behaviors.rb +25 -0
  338. data/lib/graphql/types/relay.rb +11 -3
  339. data/lib/graphql/types/string.rb +8 -2
  340. data/lib/graphql/unauthorized_error.rb +2 -2
  341. data/lib/graphql/union_type.rb +5 -25
  342. data/lib/graphql/unresolved_type_error.rb +2 -2
  343. data/lib/graphql/upgrader/member.rb +1 -0
  344. data/lib/graphql/upgrader/schema.rb +1 -0
  345. data/lib/graphql/version.rb +1 -1
  346. data/lib/graphql.rb +87 -31
  347. data/readme.md +3 -6
  348. metadata +126 -124
  349. data/lib/graphql/execution/interpreter/hash_response.rb +0 -46
  350. data/lib/graphql/literal_validation_error.rb +0 -6
  351. data/lib/graphql/types/relay/base_field.rb +0 -22
  352. data/lib/graphql/types/relay/base_interface.rb +0 -29
  353. data/lib/graphql/types/relay/base_object.rb +0 -26
@@ -8,7 +8,7 @@ module GraphQL
8
8
  # - `complexities_on_type` holds complexity scores for each type in an IRep node
9
9
  def initialize(query)
10
10
  super
11
- @complexities_on_type = [ConcreteTypeComplexity.new]
11
+ @complexities_on_type_by_query = {}
12
12
  end
13
13
 
14
14
  # Overide this method to use the complexity result
@@ -16,17 +16,68 @@ module GraphQL
16
16
  max_possible_complexity
17
17
  end
18
18
 
19
+ class ScopedTypeComplexity
20
+ # A single proc for {#scoped_children} hashes. Use this to avoid repeated allocations,
21
+ # since the lexical binding isn't important.
22
+ HASH_CHILDREN = ->(h, k) { h[k] = {} }
23
+
24
+ attr_reader :field_definition, :response_path, :query
25
+
26
+ # @param parent_type [Class] The owner of `field_definition`
27
+ # @param field_definition [GraphQL::Field, GraphQL::Schema::Field] Used for getting the `.complexity` configuration
28
+ # @param query [GraphQL::Query] Used for `query.possible_types`
29
+ # @param response_path [Array<String>] The path to the response key for the field
30
+ def initialize(parent_type, field_definition, query, response_path)
31
+ @parent_type = parent_type
32
+ @field_definition = field_definition
33
+ @query = query
34
+ @response_path = response_path
35
+ @scoped_children = nil
36
+ @nodes = []
37
+ end
38
+
39
+ # @return [Array<GraphQL::Language::Nodes::Field>]
40
+ attr_reader :nodes
41
+
42
+ # Returns true if this field has no selections, ie, it's a scalar.
43
+ # We need a quick way to check whether we should continue traversing.
44
+ def terminal?
45
+ @scoped_children.nil?
46
+ end
47
+
48
+ # This value is only calculated when asked for to avoid needless hash allocations.
49
+ # Also, if it's never asked for, we determine that this scope complexity
50
+ # is a scalar field ({#terminal?}).
51
+ # @return [Hash<Hash<Class => ScopedTypeComplexity>]
52
+ def scoped_children
53
+ @scoped_children ||= Hash.new(&HASH_CHILDREN)
54
+ end
55
+
56
+ def own_complexity(child_complexity)
57
+ @field_definition.calculate_complexity(query: @query, nodes: @nodes, child_complexity: child_complexity)
58
+ end
59
+ end
60
+
19
61
  def on_enter_field(node, parent, visitor)
20
62
  # We don't want to visit fragment definitions,
21
63
  # we'll visit them when we hit the spreads instead
22
64
  return if visitor.visiting_fragment_definition?
23
65
  return if visitor.skipping?
24
-
25
- if visitor.type_definition.kind.abstract?
26
- @complexities_on_type.push(AbstractTypeComplexity.new)
27
- else
28
- @complexities_on_type.push(ConcreteTypeComplexity.new)
29
- end
66
+ parent_type = visitor.parent_type_definition
67
+ field_key = node.alias || node.name
68
+ # Find the complexity calculation for this field --
69
+ # if we're re-entering a selection, we'll already have one.
70
+ # Otherwise, make a new one and store it.
71
+ #
72
+ # `node` and `visitor.field_definition` may appear from a cache,
73
+ # but I think that's ok. If the arguments _didn't_ match,
74
+ # then the query would have been rejected as invalid.
75
+ complexities_on_type = @complexities_on_type_by_query[visitor.query] ||= [ScopedTypeComplexity.new(nil, nil, query, visitor.response_path)]
76
+
77
+ complexity = complexities_on_type.last.scoped_children[parent_type][field_key] ||= ScopedTypeComplexity.new(parent_type, visitor.field_definition, visitor.query, visitor.response_path)
78
+ complexity.nodes.push(node)
79
+ # Push it on the stack.
80
+ complexities_on_type.push(complexity)
30
81
  end
31
82
 
32
83
  def on_leave_field(node, parent, visitor)
@@ -34,88 +85,144 @@ module GraphQL
34
85
  # we'll visit them when we hit the spreads instead
35
86
  return if visitor.visiting_fragment_definition?
36
87
  return if visitor.skipping?
88
+ complexities_on_type = @complexities_on_type_by_query[visitor.query]
89
+ complexities_on_type.pop
90
+ end
37
91
 
38
- type_complexities = @complexities_on_type.pop
39
- child_complexity = type_complexities.max_possible_complexity
40
- own_complexity = get_complexity(node, visitor.field_definition, child_complexity, visitor)
92
+ private
41
93
 
42
- if @complexities_on_type.last.is_a?(AbstractTypeComplexity)
43
- key = selection_key(visitor.response_path, visitor.query)
44
- parent_type = visitor.parent_type_definition
45
- visitor.query.possible_types(parent_type).each do |type|
46
- @complexities_on_type.last.merge(type, key, own_complexity)
47
- end
48
- else
49
- @complexities_on_type.last.merge(own_complexity)
94
+ # @return [Integer]
95
+ def max_possible_complexity
96
+ @complexities_on_type_by_query.reduce(0) do |total, (query, complexities_on_type)|
97
+ root_complexity = complexities_on_type.last
98
+ # Use this entry point to calculate the total complexity
99
+ total_complexity_for_query = merged_max_complexity_for_scopes(query, [root_complexity.scoped_children])
100
+ total + total_complexity_for_query
50
101
  end
51
102
  end
52
103
 
104
+ # @param query [GraphQL::Query] Used for `query.possible_types`
105
+ # @param scoped_children_hashes [Array<Hash>] Array of scoped children hashes
53
106
  # @return [Integer]
54
- def max_possible_complexity
55
- @complexities_on_type.last.max_possible_complexity
56
- end
107
+ def merged_max_complexity_for_scopes(query, scoped_children_hashes)
108
+ # Figure out what scopes are possible here.
109
+ # Use a hash, but ignore the values; it's just a fast way to work with the keys.
110
+ all_scopes = {}
111
+ scoped_children_hashes.each do |h|
112
+ all_scopes.merge!(h)
113
+ end
57
114
 
58
- private
115
+ # If an abstract scope is present, but _all_ of its concrete types
116
+ # are also in the list, remove it from the list of scopes to check,
117
+ # because every possible type is covered by a concrete type.
118
+ # (That is, there are no remainder types to check.)
119
+ prev_keys = all_scopes.keys
120
+ prev_keys.each do |scope|
121
+ next unless scope.kind.abstract?
122
+
123
+ missing_concrete_types = query.possible_types(scope).select { |t| !all_scopes.key?(t) }
124
+ # This concrete type is possible _only_ as a member of the abstract type.
125
+ # So, attribute to it the complexity which belongs to the abstract type.
126
+ missing_concrete_types.each do |concrete_scope|
127
+ all_scopes[concrete_scope] = all_scopes[scope]
128
+ end
129
+ all_scopes.delete(scope)
130
+ end
59
131
 
60
- def selection_key(response_path, query)
61
- # We add the query object id to support multiplex queries
62
- # even if they have the same response path, they should
63
- # always be added.
64
- "#{response_path.join(".")}-#{query.object_id}"
65
- end
132
+ # This will hold `{ type => int }` pairs, one for each possible branch
133
+ complexity_by_scope = {}
134
+
135
+ # For each scope,
136
+ # find the lexical selections that might apply to it,
137
+ # and gather them together into an array.
138
+ # Then, treat the set of selection hashes
139
+ # as a set and calculate the complexity for them as a unit
140
+ all_scopes.each do |scope, _|
141
+ # These will be the selections on `scope`
142
+ children_for_scope = []
143
+ scoped_children_hashes.each do |sc_h|
144
+ sc_h.each do |inner_scope, children_hash|
145
+ if applies_to?(query, scope, inner_scope)
146
+ children_for_scope << children_hash
147
+ end
148
+ end
149
+ end
66
150
 
67
- # Get a complexity value for a field,
68
- # by getting the number or calling its proc
69
- def get_complexity(ast_node, field_defn, child_complexity, visitor)
70
- # Return if we've visited this response path before (not counting duplicates)
71
- defined_complexity = field_defn.complexity
151
+ # Calculate the complexity for `scope`, merging all
152
+ # possible lexical branches.
153
+ complexity_value = merged_max_complexity(query, children_for_scope)
154
+ complexity_by_scope[scope] = complexity_value
155
+ end
72
156
 
73
- arguments = visitor.arguments_for(ast_node, field_defn)
157
+ # Return the max complexity among all scopes
158
+ complexity_by_scope.each_value.max
159
+ end
74
160
 
75
- case defined_complexity
76
- when Proc
77
- defined_complexity.call(visitor.query.context, arguments, child_complexity)
78
- when Numeric
79
- defined_complexity + (child_complexity || 0)
161
+ def applies_to?(query, left_scope, right_scope)
162
+ if left_scope == right_scope
163
+ # This can happen when several branches are being analyzed together
164
+ true
80
165
  else
81
- raise("Invalid complexity: #{defined_complexity.inspect} on #{field_defn.name}")
166
+ # Check if these two scopes have _any_ types in common.
167
+ possible_right_types = query.possible_types(right_scope)
168
+ possible_left_types = query.possible_types(left_scope)
169
+ !(possible_right_types & possible_left_types).empty?
82
170
  end
83
171
  end
84
172
 
85
- # Selections on an object may apply differently depending on what is _actually_ returned by the resolve function.
86
- # Find the maximum possible complexity among those combinations.
87
- class AbstractTypeComplexity
88
- def initialize
89
- @types = Hash.new { |h, k| h[k] = {} }
90
- end
173
+ # A hook which is called whenever a field's max complexity is calculated.
174
+ # Override this method to capture individual field complexity details.
175
+ #
176
+ # @param scoped_type_complexity [ScopedTypeComplexity]
177
+ # @param max_complexity [Numeric] Field's maximum complexity including child complexity
178
+ # @param child_complexity [Numeric, nil] Field's child complexity
179
+ def field_complexity(scoped_type_complexity, max_complexity:, child_complexity: nil)
180
+ end
91
181
 
92
- # Return the max possible complexity for types in this selection
93
- def max_possible_complexity
94
- max = 0
95
- @types.each_value do |fields|
96
- complexity = fields.each_value.inject(:+)
97
- max = complexity if complexity > max
98
- end
99
- max
182
+ # @param children_for_scope [Array<Hash>] An array of `scoped_children[scope]` hashes
183
+ # (`{field_key => complexity}`)
184
+ # @return [Integer] Complexity value for all these selections in the current scope
185
+ def merged_max_complexity(query, children_for_scope)
186
+ all_keys = []
187
+ children_for_scope.each do |c|
188
+ all_keys.concat(c.keys)
100
189
  end
190
+ all_keys.uniq!
191
+ complexity_for_keys = {}
192
+
193
+ all_keys.each do |child_key|
194
+ scoped_children_for_key = nil
195
+ complexity_for_key = nil
196
+ children_for_scope.each do |children_hash|
197
+ next unless children_hash.key?(child_key)
198
+
199
+ complexity_for_key = children_hash[child_key]
200
+ if complexity_for_key.terminal?
201
+ # Assume that all terminals would return the same complexity
202
+ # Since it's a terminal, its child complexity is zero.
203
+ complexity = complexity_for_key.own_complexity(0)
204
+ complexity_for_keys[child_key] = complexity
205
+
206
+ field_complexity(complexity_for_key, max_complexity: complexity, child_complexity: nil)
207
+ else
208
+ scoped_children_for_key ||= []
209
+ scoped_children_for_key << complexity_for_key.scoped_children
210
+ end
211
+ end
101
212
 
102
- # Store the complexity for the branch on `type_defn`.
103
- # Later we will see if this is the max complexity among branches.
104
- def merge(type_defn, key, complexity)
105
- @types[type_defn][key] = complexity
106
- end
107
- end
213
+ next unless scoped_children_for_key
108
214
 
109
- class ConcreteTypeComplexity
110
- attr_reader :max_possible_complexity
215
+ child_complexity = merged_max_complexity_for_scopes(query, scoped_children_for_key)
216
+ # This is the _last_ one we visited; assume it's representative.
217
+ max_complexity = complexity_for_key.own_complexity(child_complexity)
111
218
 
112
- def initialize
113
- @max_possible_complexity = 0
114
- end
219
+ field_complexity(complexity_for_key, max_complexity: max_complexity, child_complexity: child_complexity)
115
220
 
116
- def merge(complexity)
117
- @max_possible_complexity += complexity
221
+ complexity_for_keys[child_key] = max_complexity
118
222
  end
223
+
224
+ # Calculate the child complexity by summing the complexity of all selections
225
+ complexity_for_keys.each_value.inject(0, &:+)
119
226
  end
120
227
  end
121
228
  end
@@ -19,6 +19,7 @@ module GraphQL
19
19
  @field_definitions = []
20
20
  @argument_definitions = []
21
21
  @directive_definitions = []
22
+ @rescued_errors = []
22
23
  @query = query
23
24
  @schema = query.schema
24
25
  @response_path = []
@@ -32,6 +33,9 @@ module GraphQL
32
33
  # @return [Array<GraphQL::ObjectType>] Types whose scope we've entered
33
34
  attr_reader :object_types
34
35
 
36
+ # @return [Array<GraphQL::AnalysisError]
37
+ attr_reader :rescued_errors
38
+
35
39
  def visit
36
40
  return unless @document
37
41
  super
@@ -96,7 +100,8 @@ module GraphQL
96
100
  def on_field(node, parent)
97
101
  @response_path.push(node.alias || node.name)
98
102
  parent_type = @object_types.last
99
- field_definition = @schema.get_field(parent_type, node.name)
103
+ # This could be nil if the previous field wasn't found:
104
+ field_definition = parent_type && @schema.get_field(parent_type, node.name, @query.context)
100
105
  @field_definitions.push(field_definition)
101
106
  if !field_definition.nil?
102
107
  next_object_type = field_definition.type.unwrap
@@ -134,14 +139,14 @@ module GraphQL
134
139
  argument_defn = if (arg = @argument_definitions.last)
135
140
  arg_type = arg.type.unwrap
136
141
  if arg_type.kind.input_object?
137
- arg_type.input_fields[node.name]
142
+ arg_type.get_argument(node.name, @query.context)
138
143
  else
139
144
  nil
140
145
  end
141
146
  elsif (directive_defn = @directive_definitions.last)
142
- directive_defn.arguments[node.name]
147
+ directive_defn.get_argument(node.name, @query.context)
143
148
  elsif (field_defn = @field_definitions.last)
144
- field_defn.arguments[node.name]
149
+ field_defn.get_argument(node.name, @query.context)
145
150
  else
146
151
  nil
147
152
  end
@@ -214,7 +219,7 @@ module GraphQL
214
219
  fragment_def = query.fragments[fragment_spread.name]
215
220
 
216
221
  object_type = if fragment_def.type
217
- query.schema.types.fetch(fragment_def.type.name, nil)
222
+ @query.warden.get_type(fragment_def.type.name)
218
223
  else
219
224
  object_types.last
220
225
  end
@@ -239,13 +244,17 @@ module GraphQL
239
244
 
240
245
  def call_analyzers(method, node, parent)
241
246
  @analyzers.each do |analyzer|
242
- analyzer.public_send(method, node, parent, self)
247
+ begin
248
+ analyzer.public_send(method, node, parent, self)
249
+ rescue AnalysisError => err
250
+ @rescued_errors << err
251
+ end
243
252
  end
244
253
  end
245
254
 
246
255
  def on_fragment_with_type(node)
247
256
  object_type = if node.type
248
- @schema.types.fetch(node.type.name, nil)
257
+ @query.warden.get_type(node.type.name)
249
258
  else
250
259
  @object_types.last
251
260
  end
@@ -12,9 +12,13 @@ module GraphQL
12
12
  module AST
13
13
  module_function
14
14
 
15
- def use(schema_defn)
16
- schema = schema_defn.target
17
- schema.analysis_engine = GraphQL::Analysis::AST
15
+ def use(schema_class)
16
+ if schema_class.analysis_engine == self
17
+ definition_line = caller(2, 1).first
18
+ GraphQL::Deprecation.warn("GraphQL::Analysis::AST is now the default; remove `use GraphQL::Analysis::AST` from the schema definition (#{definition_line})")
19
+ else
20
+ schema_class.analysis_engine = self
21
+ end
18
22
  end
19
23
 
20
24
  # Analyze a multiplex, and all queries within.
@@ -60,16 +64,22 @@ module GraphQL
60
64
  .select { |analyzer| analyzer.analyze? }
61
65
 
62
66
  analyzers_to_run = query_analyzers + multiplex_analyzers
63
- return [] unless analyzers_to_run.any?
64
-
65
- visitor = GraphQL::Analysis::AST::Visitor.new(
66
- query: query,
67
- analyzers: analyzers_to_run
68
- )
67
+ if analyzers_to_run.any?
68
+ visitor = GraphQL::Analysis::AST::Visitor.new(
69
+ query: query,
70
+ analyzers: analyzers_to_run
71
+ )
69
72
 
70
- visitor.visit
73
+ visitor.visit
71
74
 
72
- query_analyzers.map(&:result)
75
+ if visitor.rescued_errors.any?
76
+ visitor.rescued_errors
77
+ else
78
+ query_analyzers.map(&:result)
79
+ end
80
+ else
81
+ []
82
+ end
73
83
  end
74
84
  end
75
85
 
@@ -1,48 +1,16 @@
1
1
  # frozen_string_literal: true
2
2
  module GraphQL
3
- # Used for defined arguments ({Field}, {InputObjectType})
4
- #
5
- # {#name} must be a String.
6
- #
7
- # @example defining an argument for a field
8
- # GraphQL::Field.define do
9
- # # ...
10
- # argument :favoriteFood, types.String, "Favorite thing to eat", default_value: "pizza"
11
- # end
12
- #
13
- # @example defining an argument for an {InputObjectType}
14
- # GraphQL::InputObjectType.define do
15
- # argument :newName, !types.String
16
- # end
17
- #
18
- # @example defining an argument with a `prepare` function
19
- # GraphQL::Field.define do
20
- # argument :userId, types.ID, prepare: ->(userId) do
21
- # User.find_by(id: userId)
22
- # end
23
- # end
24
- #
25
- # @example returning an {ExecutionError} from a `prepare` function
26
- # GraphQL::Field.define do
27
- # argument :date do
28
- # type !types.String
29
- # prepare ->(date) do
30
- # return GraphQL::ExecutionError.new("Invalid date format") unless DateValidator.valid?(date)
31
- # Time.zone.parse(date)
32
- # end
33
- # end
34
- # end
35
-
3
+ # @api deprecated
36
4
  class Argument
37
5
  include GraphQL::Define::InstanceDefinable
38
- accepts_definitions :name, :type, :description, :default_value, :as, :prepare, :method_access
6
+ deprecated_accepts_definitions :name, :type, :description, :default_value, :as, :prepare, :method_access, :deprecation_reason
39
7
  attr_reader :default_value
40
- attr_accessor :description, :name, :as
8
+ attr_accessor :description, :name, :as, :deprecation_reason
41
9
  attr_accessor :ast_node
42
10
  attr_accessor :method_access
43
11
  alias :graphql_name :name
44
12
 
45
- ensure_defined(:name, :description, :default_value, :type=, :type, :as, :expose_as, :prepare, :method_access)
13
+ ensure_defined(:name, :description, :default_value, :type=, :type, :as, :expose_as, :prepare, :method_access, :deprecation_reason)
46
14
 
47
15
  # @api private
48
16
  module DefaultPrepare
@@ -113,6 +81,10 @@ module GraphQL
113
81
  @prepare_proc = BackwardsCompatibility.wrap_arity(prepare_proc, from: 1, to: 2, name: "Argument#prepare(value, ctx)")
114
82
  end
115
83
 
84
+ def type_class
85
+ metadata[:type_class]
86
+ end
87
+
116
88
  NO_DEFAULT_VALUE = Object.new
117
89
  # @api private
118
90
  def self.from_dsl(name, type_or_argument = nil, description = nil, default_value: NO_DEFAULT_VALUE, as: nil, prepare: DefaultPrepare, **kwargs, &block)
@@ -1,5 +1,4 @@
1
1
  # frozen_string_literal: true
2
- # test_via: ../backtrace.rb
3
2
  module GraphQL
4
3
  class Backtrace
5
4
  module InspectResult
@@ -0,0 +1,56 @@
1
+ # frozen_string_literal: true
2
+ module GraphQL
3
+ class Backtrace
4
+ module LegacyTracer
5
+ module_function
6
+
7
+ # Implement the {GraphQL::Tracing} API.
8
+ def trace(key, metadata)
9
+ case key
10
+ when "lex", "parse"
11
+ # No context here, don't have a query yet
12
+ nil
13
+ when "execute_multiplex", "analyze_multiplex"
14
+ # No query context yet
15
+ nil
16
+ when "validate", "analyze_query", "execute_query", "execute_query_lazy"
17
+ query = metadata[:query] || metadata[:queries].first
18
+ push_data = query
19
+ multiplex = query.multiplex
20
+ when "execute_field", "execute_field_lazy"
21
+ # The interpreter passes `query:`, legacy passes `context:`
22
+ context = metadata[:context] || ((q = metadata[:query]) && q.context)
23
+ push_data = context
24
+ multiplex = context.query.multiplex
25
+ else
26
+ # Custom key, no backtrace data for this
27
+ nil
28
+ end
29
+
30
+ if push_data
31
+ multiplex.context[:last_graphql_backtrace_context] = push_data
32
+ end
33
+
34
+ if key == "execute_multiplex"
35
+ begin
36
+ yield
37
+ rescue StandardError => err
38
+ # This is an unhandled error from execution,
39
+ # Re-raise it with a GraphQL trace.
40
+ potential_context = metadata[:multiplex].context[:last_graphql_backtrace_context]
41
+
42
+ if potential_context.is_a?(GraphQL::Query::Context) || potential_context.is_a?(GraphQL::Query::Context::FieldResolutionContext)
43
+ raise TracedError.new(err, potential_context)
44
+ else
45
+ raise
46
+ end
47
+ ensure
48
+ metadata[:multiplex].context.delete(:last_graphql_backtrace_context)
49
+ end
50
+ else
51
+ yield
52
+ end
53
+ end
54
+ end
55
+ end
56
+ end
@@ -1,5 +1,4 @@
1
1
  # frozen_string_literal: true
2
- # test_via: ../backtrace.rb
3
2
  module GraphQL
4
3
  class Backtrace
5
4
  # A class for turning a context into a human-readable table or array
@@ -79,15 +78,38 @@ module GraphQL
79
78
  # @return [Array] 5 items for a backtrace table (not `key`)
80
79
  def build_rows(context_entry, rows:, top: false)
81
80
  case context_entry
81
+ when Backtrace::Frame
82
+ field_alias = context_entry.ast_node.respond_to?(:alias) && context_entry.ast_node.alias
83
+ value = if top && @override_value
84
+ @override_value
85
+ else
86
+ value_at(@context.query.context.namespace(:interpreter)[:runtime], context_entry.path)
87
+ end
88
+ rows << [
89
+ "#{context_entry.ast_node ? context_entry.ast_node.position.join(":") : ""}",
90
+ "#{context_entry.field.path}#{field_alias ? " as #{field_alias}" : ""}",
91
+ "#{context_entry.object.object.inspect}",
92
+ context_entry.arguments.to_h.inspect, # rubocop:disable Development/ContextIsPassedCop -- unrelated method
93
+ Backtrace::InspectResult.inspect_result(value),
94
+ ]
95
+ if (parent = context_entry.parent_frame)
96
+ build_rows(parent, rows: rows)
97
+ else
98
+ rows
99
+ end
82
100
  when GraphQL::Query::Context::FieldResolutionContext
83
101
  ctx = context_entry
84
102
  field_name = "#{ctx.irep_node.owner_type.name}.#{ctx.field.name}"
85
103
  position = "#{ctx.ast_node.line}:#{ctx.ast_node.col}"
86
104
  field_alias = ctx.ast_node.alias
105
+ object = ctx.object
106
+ if object.is_a?(GraphQL::Schema::Object)
107
+ object = object.object
108
+ end
87
109
  rows << [
88
110
  "#{position}",
89
111
  "#{field_name}#{field_alias ? " as #{field_alias}" : ""}",
90
- "#{ctx.object.inspect}",
112
+ "#{object.inspect}",
91
113
  ctx.irep_node.arguments.to_h.inspect,
92
114
  Backtrace::InspectResult.inspect_result(top && @override_value ? @override_value : ctx.value),
93
115
  ]
@@ -104,16 +126,33 @@ module GraphQL
104
126
  position = "?:?"
105
127
  end
106
128
  op_name = query.selected_operation_name
129
+ object = query.root_value
130
+ if object.is_a?(GraphQL::Schema::Object)
131
+ object = object.object
132
+ end
133
+ value = value_at(context_entry.namespace(:interpreter)[:runtime], [])
107
134
  rows << [
108
135
  "#{position}",
109
136
  "#{op_type}#{op_name ? " #{op_name}" : ""}",
110
- "#{query.root_value.inspect}",
137
+ "#{object.inspect}",
111
138
  query.variables.to_h.inspect,
112
- Backtrace::InspectResult.inspect_result(query.context.value),
139
+ Backtrace::InspectResult.inspect_result(value),
113
140
  ]
114
141
  else
115
- raise "Unexpected get_rows subject #{context_entry.inspect}"
142
+ raise "Unexpected get_rows subject #{context_entry.class} (#{context_entry.inspect})"
143
+ end
144
+ end
145
+
146
+ def value_at(runtime, path)
147
+ response = runtime.final_result
148
+ path.each do |key|
149
+ if response && (response = response[key])
150
+ next
151
+ else
152
+ break
153
+ end
116
154
  end
155
+ response
117
156
  end
118
157
  end
119
158
  end
@@ -1,5 +1,4 @@
1
1
  # frozen_string_literal: true
2
- # test_via: ../backtrace.rb
3
2
  module GraphQL
4
3
  class Backtrace
5
4
  # When {Backtrace} is enabled, raised errors are wrapped with {TracedError}.