graphql 1.9.21 → 2.0.16

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.

Potentially problematic release.


This version of graphql might be problematic. Click here for more details.

Files changed (403) 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 +45 -8
  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 +49 -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 +25 -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/ast/field_usage.rb +31 -2
  49. data/lib/graphql/analysis/ast/max_query_complexity.rb +0 -1
  50. data/lib/graphql/analysis/ast/query_complexity.rb +175 -68
  51. data/lib/graphql/analysis/ast/query_depth.rb +0 -1
  52. data/lib/graphql/analysis/ast/visitor.rb +17 -8
  53. data/lib/graphql/analysis/ast.rb +14 -14
  54. data/lib/graphql/analysis.rb +0 -7
  55. data/lib/graphql/backtrace/inspect_result.rb +0 -1
  56. data/lib/graphql/backtrace/table.rb +37 -16
  57. data/lib/graphql/backtrace/traced_error.rb +0 -1
  58. data/lib/graphql/backtrace/tracer.rb +39 -9
  59. data/lib/graphql/backtrace.rb +20 -17
  60. data/lib/graphql/dataloader/null_dataloader.rb +24 -0
  61. data/lib/graphql/dataloader/request.rb +19 -0
  62. data/lib/graphql/dataloader/request_all.rb +19 -0
  63. data/lib/graphql/dataloader/source.rb +164 -0
  64. data/lib/graphql/dataloader.rb +311 -0
  65. data/lib/graphql/date_encoding_error.rb +16 -0
  66. data/lib/graphql/deprecation.rb +9 -0
  67. data/lib/graphql/dig.rb +1 -1
  68. data/lib/graphql/execution/directive_checks.rb +2 -2
  69. data/lib/graphql/execution/errors.rb +77 -45
  70. data/lib/graphql/execution/interpreter/argument_value.rb +28 -0
  71. data/lib/graphql/execution/interpreter/arguments.rb +88 -0
  72. data/lib/graphql/execution/interpreter/arguments_cache.rb +105 -0
  73. data/lib/graphql/execution/interpreter/handles_raw_value.rb +18 -0
  74. data/lib/graphql/execution/interpreter/resolve.rb +44 -25
  75. data/lib/graphql/execution/interpreter/runtime.rb +755 -395
  76. data/lib/graphql/execution/interpreter.rb +201 -74
  77. data/lib/graphql/execution/lazy/lazy_method_map.rb +4 -0
  78. data/lib/graphql/execution/lazy.rb +5 -9
  79. data/lib/graphql/execution/lookahead.rb +65 -136
  80. data/lib/graphql/execution/multiplex.rb +5 -152
  81. data/lib/graphql/execution.rb +11 -4
  82. data/lib/graphql/filter.rb +1 -1
  83. data/lib/graphql/integer_decoding_error.rb +17 -0
  84. data/lib/graphql/integer_encoding_error.rb +18 -2
  85. data/lib/graphql/introspection/base_object.rb +2 -5
  86. data/lib/graphql/introspection/directive_location_enum.rb +2 -2
  87. data/lib/graphql/introspection/directive_type.rb +11 -5
  88. data/lib/graphql/introspection/dynamic_fields.rb +3 -8
  89. data/lib/graphql/introspection/entry_points.rb +5 -18
  90. data/lib/graphql/introspection/enum_value_type.rb +2 -2
  91. data/lib/graphql/introspection/field_type.rb +9 -5
  92. data/lib/graphql/introspection/input_value_type.rb +41 -11
  93. data/lib/graphql/introspection/introspection_query.rb +6 -92
  94. data/lib/graphql/introspection/schema_type.rb +10 -10
  95. data/lib/graphql/introspection/type_type.rb +34 -17
  96. data/lib/graphql/introspection.rb +100 -0
  97. data/lib/graphql/invalid_null_error.rb +18 -0
  98. data/lib/graphql/language/block_string.rb +20 -5
  99. data/lib/graphql/language/cache.rb +37 -0
  100. data/lib/graphql/language/definition_slice.rb +21 -10
  101. data/lib/graphql/language/document_from_schema_definition.rb +104 -68
  102. data/lib/graphql/language/lexer.rb +83 -40
  103. data/lib/graphql/language/lexer.rl +31 -9
  104. data/lib/graphql/language/nodes.rb +64 -93
  105. data/lib/graphql/language/parser.rb +940 -896
  106. data/lib/graphql/language/parser.y +130 -103
  107. data/lib/graphql/language/printer.rb +48 -23
  108. data/lib/graphql/language/sanitized_printer.rb +222 -0
  109. data/lib/graphql/language/token.rb +0 -4
  110. data/lib/graphql/language/visitor.rb +2 -2
  111. data/lib/graphql/language.rb +3 -1
  112. data/lib/graphql/name_validator.rb +2 -7
  113. data/lib/graphql/pagination/active_record_relation_connection.rb +85 -0
  114. data/lib/graphql/pagination/array_connection.rb +79 -0
  115. data/lib/graphql/pagination/connection.rb +253 -0
  116. data/lib/graphql/pagination/connections.rb +135 -0
  117. data/lib/graphql/pagination/mongoid_relation_connection.rb +25 -0
  118. data/lib/graphql/pagination/relation_connection.rb +228 -0
  119. data/lib/graphql/pagination/sequel_dataset_connection.rb +28 -0
  120. data/lib/graphql/pagination.rb +6 -0
  121. data/lib/graphql/parse_error.rb +0 -1
  122. data/lib/graphql/query/context.rb +172 -198
  123. data/lib/graphql/query/fingerprint.rb +26 -0
  124. data/lib/graphql/query/input_validation_result.rb +33 -7
  125. data/lib/graphql/query/null_context.rb +21 -8
  126. data/lib/graphql/query/validation_pipeline.rb +16 -38
  127. data/lib/graphql/query/variable_validation_error.rb +3 -3
  128. data/lib/graphql/query/variables.rb +39 -12
  129. data/lib/graphql/query.rb +74 -38
  130. data/lib/graphql/railtie.rb +6 -102
  131. data/lib/graphql/rake_task/validate.rb +4 -1
  132. data/lib/graphql/rake_task.rb +41 -10
  133. data/lib/graphql/relay/range_add.rb +17 -10
  134. data/lib/graphql/relay.rb +0 -15
  135. data/lib/graphql/rubocop/graphql/base_cop.rb +36 -0
  136. data/lib/graphql/rubocop/graphql/default_null_true.rb +43 -0
  137. data/lib/graphql/rubocop/graphql/default_required_true.rb +43 -0
  138. data/lib/graphql/rubocop.rb +4 -0
  139. data/lib/graphql/schema/addition.rb +245 -0
  140. data/lib/graphql/schema/argument.rb +286 -31
  141. data/lib/graphql/schema/base_64_encoder.rb +2 -0
  142. data/lib/graphql/schema/build_from_definition/resolve_map/default_resolve.rb +1 -1
  143. data/lib/graphql/schema/build_from_definition/resolve_map.rb +13 -5
  144. data/lib/graphql/schema/build_from_definition.rb +334 -220
  145. data/lib/graphql/schema/built_in_types.rb +5 -5
  146. data/lib/graphql/schema/directive/deprecated.rb +18 -0
  147. data/lib/graphql/schema/directive/feature.rb +1 -1
  148. data/lib/graphql/schema/directive/flagged.rb +57 -0
  149. data/lib/graphql/schema/directive/include.rb +2 -2
  150. data/lib/graphql/schema/directive/one_of.rb +12 -0
  151. data/lib/graphql/schema/directive/skip.rb +2 -2
  152. data/lib/graphql/schema/directive/transform.rb +14 -2
  153. data/lib/graphql/schema/directive.rb +117 -14
  154. data/lib/graphql/schema/enum.rb +113 -22
  155. data/lib/graphql/schema/enum_value.rb +16 -21
  156. data/lib/graphql/schema/field/connection_extension.rb +50 -20
  157. data/lib/graphql/schema/field/scope_extension.rb +1 -1
  158. data/lib/graphql/schema/field.rb +491 -329
  159. data/lib/graphql/schema/field_extension.rb +89 -2
  160. data/lib/graphql/schema/find_inherited_value.rb +17 -1
  161. data/lib/graphql/schema/finder.rb +16 -14
  162. data/lib/graphql/schema/input_object.rb +182 -60
  163. data/lib/graphql/schema/interface.rb +28 -43
  164. data/lib/graphql/schema/introspection_system.rb +101 -38
  165. data/lib/graphql/schema/late_bound_type.rb +7 -2
  166. data/lib/graphql/schema/list.rb +61 -3
  167. data/lib/graphql/schema/loader.rb +144 -102
  168. data/lib/graphql/schema/member/base_dsl_methods.rb +33 -32
  169. data/lib/graphql/schema/member/build_type.rb +24 -15
  170. data/lib/graphql/schema/member/has_arguments.rb +261 -24
  171. data/lib/graphql/schema/member/has_ast_node.rb +20 -0
  172. data/lib/graphql/schema/member/has_deprecation_reason.rb +25 -0
  173. data/lib/graphql/schema/member/has_directives.rb +113 -0
  174. data/lib/graphql/schema/member/has_fields.rb +99 -34
  175. data/lib/graphql/schema/member/has_interfaces.rb +88 -0
  176. data/lib/graphql/schema/member/has_unresolved_type_error.rb +15 -0
  177. data/lib/graphql/schema/member/has_validators.rb +31 -0
  178. data/lib/graphql/schema/member/relay_shortcuts.rb +28 -2
  179. data/lib/graphql/schema/member/type_system_helpers.rb +3 -3
  180. data/lib/graphql/schema/member/validates_input.rb +33 -0
  181. data/lib/graphql/schema/member.rb +11 -6
  182. data/lib/graphql/schema/mutation.rb +4 -9
  183. data/lib/graphql/schema/non_null.rb +34 -4
  184. data/lib/graphql/schema/object.rb +38 -60
  185. data/lib/graphql/schema/printer.rb +16 -35
  186. data/lib/graphql/schema/relay_classic_mutation.rb +90 -43
  187. data/lib/graphql/schema/resolver/has_payload_type.rb +46 -6
  188. data/lib/graphql/schema/resolver.rb +146 -93
  189. data/lib/graphql/schema/scalar.rb +40 -15
  190. data/lib/graphql/schema/subscription.rb +55 -26
  191. data/lib/graphql/schema/timeout.rb +29 -15
  192. data/lib/graphql/schema/type_expression.rb +21 -13
  193. data/lib/graphql/schema/type_membership.rb +22 -5
  194. data/lib/graphql/schema/union.rb +48 -14
  195. data/lib/graphql/schema/unique_within_type.rb +1 -2
  196. data/lib/graphql/schema/validator/allow_blank_validator.rb +29 -0
  197. data/lib/graphql/schema/validator/allow_null_validator.rb +26 -0
  198. data/lib/graphql/schema/validator/exclusion_validator.rb +33 -0
  199. data/lib/graphql/schema/validator/format_validator.rb +48 -0
  200. data/lib/graphql/schema/validator/inclusion_validator.rb +35 -0
  201. data/lib/graphql/schema/validator/length_validator.rb +59 -0
  202. data/lib/graphql/schema/validator/numericality_validator.rb +82 -0
  203. data/lib/graphql/schema/validator/required_validator.rb +82 -0
  204. data/lib/graphql/schema/validator.rb +171 -0
  205. data/lib/graphql/schema/warden.rb +187 -33
  206. data/lib/graphql/schema/wrapper.rb +0 -5
  207. data/lib/graphql/schema.rb +773 -892
  208. data/lib/graphql/static_validation/all_rules.rb +3 -0
  209. data/lib/graphql/static_validation/base_visitor.rb +21 -31
  210. data/lib/graphql/static_validation/definition_dependencies.rb +7 -2
  211. data/lib/graphql/static_validation/error.rb +3 -1
  212. data/lib/graphql/static_validation/literal_validator.rb +55 -26
  213. data/lib/graphql/static_validation/rules/argument_literals_are_compatible.rb +45 -83
  214. data/lib/graphql/static_validation/rules/argument_literals_are_compatible_error.rb +22 -6
  215. data/lib/graphql/static_validation/rules/arguments_are_defined.rb +35 -26
  216. data/lib/graphql/static_validation/rules/arguments_are_defined_error.rb +4 -2
  217. data/lib/graphql/static_validation/rules/directives_are_defined.rb +12 -6
  218. data/lib/graphql/static_validation/rules/directives_are_in_valid_locations.rb +14 -14
  219. data/lib/graphql/static_validation/rules/fields_are_defined_on_type.rb +4 -4
  220. data/lib/graphql/static_validation/rules/fields_have_appropriate_selections.rb +5 -5
  221. data/lib/graphql/static_validation/rules/fields_will_merge.rb +94 -51
  222. data/lib/graphql/static_validation/rules/fields_will_merge_error.rb +25 -4
  223. data/lib/graphql/static_validation/rules/fragment_spreads_are_possible.rb +3 -3
  224. data/lib/graphql/static_validation/rules/fragments_are_finite.rb +2 -2
  225. data/lib/graphql/static_validation/rules/input_object_names_are_unique.rb +30 -0
  226. data/lib/graphql/static_validation/rules/input_object_names_are_unique_error.rb +30 -0
  227. data/lib/graphql/static_validation/rules/one_of_input_objects_are_valid.rb +66 -0
  228. data/lib/graphql/static_validation/rules/one_of_input_objects_are_valid_error.rb +29 -0
  229. data/lib/graphql/static_validation/rules/query_root_exists.rb +17 -0
  230. data/lib/graphql/static_validation/rules/query_root_exists_error.rb +26 -0
  231. data/lib/graphql/static_validation/rules/required_arguments_are_present.rb +4 -2
  232. data/lib/graphql/static_validation/rules/required_input_object_attributes_are_present.rb +9 -10
  233. data/lib/graphql/static_validation/rules/unique_directives_per_location.rb +13 -7
  234. data/lib/graphql/static_validation/rules/variable_default_values_are_correctly_typed.rb +12 -13
  235. data/lib/graphql/static_validation/rules/variable_usages_are_allowed.rb +19 -14
  236. data/lib/graphql/static_validation/rules/variables_are_input_types.rb +1 -1
  237. data/lib/graphql/static_validation/rules/variables_are_used_and_defined.rb +5 -3
  238. data/lib/graphql/static_validation/type_stack.rb +2 -2
  239. data/lib/graphql/static_validation/validation_context.rb +13 -3
  240. data/lib/graphql/static_validation/validation_timeout_error.rb +25 -0
  241. data/lib/graphql/static_validation/validator.rb +31 -19
  242. data/lib/graphql/static_validation.rb +1 -2
  243. data/lib/graphql/string_encoding_error.rb +13 -3
  244. data/lib/graphql/subscriptions/action_cable_subscriptions.rb +129 -22
  245. data/lib/graphql/subscriptions/broadcast_analyzer.rb +81 -0
  246. data/lib/graphql/subscriptions/default_subscription_resolve_extension.rb +58 -0
  247. data/lib/graphql/subscriptions/event.rb +85 -31
  248. data/lib/graphql/subscriptions/instrumentation.rb +0 -47
  249. data/lib/graphql/subscriptions/serialize.rb +53 -6
  250. data/lib/graphql/subscriptions.rb +137 -57
  251. data/lib/graphql/tracing/active_support_notifications_tracing.rb +8 -17
  252. data/lib/graphql/tracing/appoptics_tracing.rb +173 -0
  253. data/lib/graphql/tracing/appsignal_tracing.rb +23 -0
  254. data/lib/graphql/tracing/data_dog_tracing.rb +34 -2
  255. data/lib/graphql/tracing/new_relic_tracing.rb +9 -12
  256. data/lib/graphql/tracing/notifications_tracing.rb +59 -0
  257. data/lib/graphql/tracing/platform_tracing.rb +67 -38
  258. data/lib/graphql/tracing/prometheus_tracing/graphql_collector.rb +4 -1
  259. data/lib/graphql/tracing/prometheus_tracing.rb +8 -0
  260. data/lib/graphql/tracing/scout_tracing.rb +19 -0
  261. data/lib/graphql/tracing/statsd_tracing.rb +42 -0
  262. data/lib/graphql/tracing.rb +15 -36
  263. data/lib/graphql/types/big_int.rb +5 -1
  264. data/lib/graphql/types/int.rb +10 -3
  265. data/lib/graphql/types/iso_8601_date.rb +20 -9
  266. data/lib/graphql/types/iso_8601_date_time.rb +36 -10
  267. data/lib/graphql/types/relay/base_connection.rb +18 -90
  268. data/lib/graphql/types/relay/base_edge.rb +2 -34
  269. data/lib/graphql/types/relay/connection_behaviors.rb +158 -0
  270. data/lib/graphql/types/relay/default_relay.rb +27 -0
  271. data/lib/graphql/types/relay/edge_behaviors.rb +65 -0
  272. data/lib/graphql/types/relay/has_node_field.rb +41 -0
  273. data/lib/graphql/types/relay/has_nodes_field.rb +41 -0
  274. data/lib/graphql/types/relay/node.rb +2 -4
  275. data/lib/graphql/types/relay/node_behaviors.rb +19 -0
  276. data/lib/graphql/types/relay/page_info.rb +2 -14
  277. data/lib/graphql/types/relay/page_info_behaviors.rb +25 -0
  278. data/lib/graphql/types/relay.rb +11 -5
  279. data/lib/graphql/types/string.rb +8 -2
  280. data/lib/graphql/unauthorized_error.rb +2 -2
  281. data/lib/graphql/unresolved_type_error.rb +2 -2
  282. data/lib/graphql/version.rb +1 -1
  283. data/lib/graphql.rb +41 -58
  284. data/readme.md +3 -6
  285. metadata +103 -237
  286. data/lib/graphql/analysis/analyze_query.rb +0 -91
  287. data/lib/graphql/analysis/field_usage.rb +0 -45
  288. data/lib/graphql/analysis/max_query_complexity.rb +0 -26
  289. data/lib/graphql/analysis/max_query_depth.rb +0 -26
  290. data/lib/graphql/analysis/query_complexity.rb +0 -88
  291. data/lib/graphql/analysis/query_depth.rb +0 -43
  292. data/lib/graphql/analysis/reducer_state.rb +0 -48
  293. data/lib/graphql/argument.rb +0 -159
  294. data/lib/graphql/authorization.rb +0 -82
  295. data/lib/graphql/backwards_compatibility.rb +0 -60
  296. data/lib/graphql/base_type.rb +0 -226
  297. data/lib/graphql/boolean_type.rb +0 -2
  298. data/lib/graphql/compatibility/execution_specification/counter_schema.rb +0 -53
  299. data/lib/graphql/compatibility/execution_specification/specification_schema.rb +0 -200
  300. data/lib/graphql/compatibility/execution_specification.rb +0 -435
  301. data/lib/graphql/compatibility/lazy_execution_specification/lazy_schema.rb +0 -111
  302. data/lib/graphql/compatibility/lazy_execution_specification.rb +0 -213
  303. data/lib/graphql/compatibility/query_parser_specification/parse_error_specification.rb +0 -91
  304. data/lib/graphql/compatibility/query_parser_specification/query_assertions.rb +0 -79
  305. data/lib/graphql/compatibility/query_parser_specification.rb +0 -264
  306. data/lib/graphql/compatibility/schema_parser_specification.rb +0 -680
  307. data/lib/graphql/compatibility.rb +0 -5
  308. data/lib/graphql/define/assign_argument.rb +0 -12
  309. data/lib/graphql/define/assign_connection.rb +0 -13
  310. data/lib/graphql/define/assign_enum_value.rb +0 -18
  311. data/lib/graphql/define/assign_global_id_field.rb +0 -11
  312. data/lib/graphql/define/assign_mutation_function.rb +0 -34
  313. data/lib/graphql/define/assign_object_field.rb +0 -42
  314. data/lib/graphql/define/defined_object_proxy.rb +0 -53
  315. data/lib/graphql/define/instance_definable.rb +0 -311
  316. data/lib/graphql/define/no_definition_error.rb +0 -7
  317. data/lib/graphql/define/non_null_with_bang.rb +0 -16
  318. data/lib/graphql/define/type_definer.rb +0 -31
  319. data/lib/graphql/define.rb +0 -31
  320. data/lib/graphql/deprecated_dsl.rb +0 -42
  321. data/lib/graphql/directive/deprecated_directive.rb +0 -13
  322. data/lib/graphql/directive/include_directive.rb +0 -2
  323. data/lib/graphql/directive/skip_directive.rb +0 -2
  324. data/lib/graphql/directive.rb +0 -104
  325. data/lib/graphql/enum_type.rb +0 -193
  326. data/lib/graphql/execution/execute.rb +0 -326
  327. data/lib/graphql/execution/flatten.rb +0 -40
  328. data/lib/graphql/execution/instrumentation.rb +0 -92
  329. data/lib/graphql/execution/interpreter/hash_response.rb +0 -46
  330. data/lib/graphql/execution/lazy/resolve.rb +0 -91
  331. data/lib/graphql/execution/typecast.rb +0 -50
  332. data/lib/graphql/field/resolve.rb +0 -59
  333. data/lib/graphql/field.rb +0 -330
  334. data/lib/graphql/float_type.rb +0 -2
  335. data/lib/graphql/function.rb +0 -153
  336. data/lib/graphql/id_type.rb +0 -2
  337. data/lib/graphql/input_object_type.rb +0 -154
  338. data/lib/graphql/int_type.rb +0 -2
  339. data/lib/graphql/interface_type.rb +0 -86
  340. data/lib/graphql/internal_representation/document.rb +0 -27
  341. data/lib/graphql/internal_representation/node.rb +0 -206
  342. data/lib/graphql/internal_representation/print.rb +0 -51
  343. data/lib/graphql/internal_representation/rewrite.rb +0 -184
  344. data/lib/graphql/internal_representation/scope.rb +0 -88
  345. data/lib/graphql/internal_representation/visit.rb +0 -36
  346. data/lib/graphql/internal_representation.rb +0 -7
  347. data/lib/graphql/list_type.rb +0 -80
  348. data/lib/graphql/literal_validation_error.rb +0 -6
  349. data/lib/graphql/non_null_type.rb +0 -81
  350. data/lib/graphql/object_type.rb +0 -141
  351. data/lib/graphql/query/arguments.rb +0 -187
  352. data/lib/graphql/query/arguments_cache.rb +0 -25
  353. data/lib/graphql/query/executor.rb +0 -53
  354. data/lib/graphql/query/literal_input.rb +0 -116
  355. data/lib/graphql/query/serial_execution/field_resolution.rb +0 -92
  356. data/lib/graphql/query/serial_execution/operation_resolution.rb +0 -19
  357. data/lib/graphql/query/serial_execution/selection_resolution.rb +0 -23
  358. data/lib/graphql/query/serial_execution/value_resolution.rb +0 -87
  359. data/lib/graphql/query/serial_execution.rb +0 -39
  360. data/lib/graphql/relay/array_connection.rb +0 -85
  361. data/lib/graphql/relay/base_connection.rb +0 -172
  362. data/lib/graphql/relay/connection_instrumentation.rb +0 -54
  363. data/lib/graphql/relay/connection_resolve.rb +0 -43
  364. data/lib/graphql/relay/connection_type.rb +0 -40
  365. data/lib/graphql/relay/edge.rb +0 -27
  366. data/lib/graphql/relay/edge_type.rb +0 -18
  367. data/lib/graphql/relay/edges_instrumentation.rb +0 -40
  368. data/lib/graphql/relay/global_id_resolve.rb +0 -18
  369. data/lib/graphql/relay/mongo_relation_connection.rb +0 -50
  370. data/lib/graphql/relay/mutation/instrumentation.rb +0 -23
  371. data/lib/graphql/relay/mutation/resolve.rb +0 -56
  372. data/lib/graphql/relay/mutation/result.rb +0 -38
  373. data/lib/graphql/relay/mutation.rb +0 -190
  374. data/lib/graphql/relay/node.rb +0 -36
  375. data/lib/graphql/relay/page_info.rb +0 -7
  376. data/lib/graphql/relay/relation_connection.rb +0 -190
  377. data/lib/graphql/relay/type_extensions.rb +0 -30
  378. data/lib/graphql/scalar_type.rb +0 -133
  379. data/lib/graphql/schema/catchall_middleware.rb +0 -35
  380. data/lib/graphql/schema/default_parse_error.rb +0 -10
  381. data/lib/graphql/schema/default_type_error.rb +0 -15
  382. data/lib/graphql/schema/member/accepts_definition.rb +0 -152
  383. data/lib/graphql/schema/member/cached_graphql_definition.rb +0 -26
  384. data/lib/graphql/schema/member/instrumentation.rb +0 -132
  385. data/lib/graphql/schema/middleware_chain.rb +0 -82
  386. data/lib/graphql/schema/possible_types.rb +0 -39
  387. data/lib/graphql/schema/rescue_middleware.rb +0 -60
  388. data/lib/graphql/schema/timeout_middleware.rb +0 -86
  389. data/lib/graphql/schema/traversal.rb +0 -228
  390. data/lib/graphql/schema/validation.rb +0 -303
  391. data/lib/graphql/static_validation/default_visitor.rb +0 -15
  392. data/lib/graphql/static_validation/no_validate_visitor.rb +0 -10
  393. data/lib/graphql/string_type.rb +0 -2
  394. data/lib/graphql/subscriptions/subscription_root.rb +0 -74
  395. data/lib/graphql/tracing/skylight_tracing.rb +0 -62
  396. data/lib/graphql/types/relay/base_field.rb +0 -22
  397. data/lib/graphql/types/relay/base_interface.rb +0 -29
  398. data/lib/graphql/types/relay/base_object.rb +0 -26
  399. data/lib/graphql/types/relay/node_field.rb +0 -43
  400. data/lib/graphql/types/relay/nodes_field.rb +0 -45
  401. data/lib/graphql/union_type.rb +0 -135
  402. data/lib/graphql/upgrader/member.rb +0 -936
  403. data/lib/graphql/upgrader/schema.rb +0 -37
@@ -5,10 +5,10 @@ module GraphQL
5
5
  module AST
6
6
  class QueryComplexity < Analyzer
7
7
  # State for the query complexity calculation:
8
- # - `complexities_on_type` holds complexity scores for each type in an IRep node
8
+ # - `complexities_on_type` holds complexity scores for each type
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
@@ -15,7 +15,6 @@ module GraphQL
15
15
  # # In your Schema file:
16
16
  #
17
17
  # class MySchema < GraphQL::Schema
18
- # use GraphQL::Analysis::AST
19
18
  # query_analyzer LogQueryDepth
20
19
  # end
21
20
  #
@@ -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
@@ -39,7 +43,7 @@ module GraphQL
39
43
 
40
44
  # Visit Helpers
41
45
 
42
- # @return [GraphQL::Query::Arguments] Arguments for this node, merging default values, literal values and query variables
46
+ # @return [GraphQL::Execution::Interpreter::Arguments] Arguments for this node, merging default values, literal values and query variables
43
47
  # @see {GraphQL::Query#arguments_for}
44
48
  def arguments_for(ast_node, field_definition)
45
49
  @query.arguments_for(ast_node, field_definition)
@@ -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
@@ -11,12 +11,6 @@ module GraphQL
11
11
  module Analysis
12
12
  module AST
13
13
  module_function
14
-
15
- def use(schema_defn)
16
- schema = schema_defn.target
17
- schema.analysis_engine = GraphQL::Analysis::AST
18
- end
19
-
20
14
  # Analyze a multiplex, and all queries within.
21
15
  # Multiplex analyzers are ran for all queries, keeping state.
22
16
  # Query analyzers are ran per query, without carrying state between queries.
@@ -60,16 +54,22 @@ module GraphQL
60
54
  .select { |analyzer| analyzer.analyze? }
61
55
 
62
56
  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
- )
57
+ if analyzers_to_run.any?
58
+ visitor = GraphQL::Analysis::AST::Visitor.new(
59
+ query: query,
60
+ analyzers: analyzers_to_run
61
+ )
69
62
 
70
- visitor.visit
63
+ visitor.visit
71
64
 
72
- query_analyzers.map(&:result)
65
+ if visitor.rescued_errors.any?
66
+ visitor.rescued_errors
67
+ else
68
+ query_analyzers.map(&:result)
69
+ end
70
+ else
71
+ []
72
+ end
73
73
  end
74
74
  end
75
75
 
@@ -1,9 +1,2 @@
1
1
  # frozen_string_literal: true
2
2
  require "graphql/analysis/ast"
3
- require "graphql/analysis/max_query_complexity"
4
- require "graphql/analysis/max_query_depth"
5
- require "graphql/analysis/query_complexity"
6
- require "graphql/analysis/query_depth"
7
- require "graphql/analysis/reducer_state"
8
- require "graphql/analysis/analyze_query"
9
- require "graphql/analysis/field_usage"
@@ -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
@@ -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,20 +78,25 @@ 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
82
- when GraphQL::Query::Context::FieldResolutionContext
83
- ctx = context_entry
84
- field_name = "#{ctx.irep_node.owner_type.name}.#{ctx.field.name}"
85
- position = "#{ctx.ast_node.line}:#{ctx.ast_node.col}"
86
- field_alias = ctx.ast_node.alias
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)[:runtime], context_entry.path)
87
+ end
87
88
  rows << [
88
- "#{position}",
89
- "#{field_name}#{field_alias ? " as #{field_alias}" : ""}",
90
- "#{ctx.object.inspect}",
91
- ctx.irep_node.arguments.to_h.inspect,
92
- Backtrace::InspectResult.inspect_result(top && @override_value ? @override_value : ctx.value),
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),
93
94
  ]
94
-
95
- build_rows(ctx.parent, rows: rows)
95
+ if (parent = context_entry.parent_frame)
96
+ build_rows(parent, rows: rows)
97
+ else
98
+ rows
99
+ end
96
100
  when GraphQL::Query::Context
97
101
  query = context_entry.query
98
102
  op = query.selected_operation
@@ -104,16 +108,33 @@ module GraphQL
104
108
  position = "?:?"
105
109
  end
106
110
  op_name = query.selected_operation_name
111
+ object = query.root_value
112
+ if object.is_a?(GraphQL::Schema::Object)
113
+ object = object.object
114
+ end
115
+ value = value_at(context_entry.namespace(:interpreter_runtime)[:runtime], [])
107
116
  rows << [
108
117
  "#{position}",
109
118
  "#{op_type}#{op_name ? " #{op_name}" : ""}",
110
- "#{query.root_value.inspect}",
119
+ "#{object.inspect}",
111
120
  query.variables.to_h.inspect,
112
- Backtrace::InspectResult.inspect_result(query.context.value),
121
+ Backtrace::InspectResult.inspect_result(value),
113
122
  ]
114
123
  else
115
- raise "Unexpected get_rows subject #{context_entry.inspect}"
124
+ raise "Unexpected get_rows subject #{context_entry.class} (#{context_entry.inspect})"
125
+ end
126
+ end
127
+
128
+ def value_at(runtime, path)
129
+ response = runtime.final_result
130
+ path.each do |key|
131
+ if response && (response = response[key])
132
+ next
133
+ else
134
+ break
135
+ end
116
136
  end
137
+ response
117
138
  end
118
139
  end
119
140
  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}.
@@ -1,45 +1,75 @@
1
1
  # frozen_string_literal: true
2
2
  module GraphQL
3
3
  class Backtrace
4
+ # TODO this is not fiber-friendly
4
5
  module Tracer
5
6
  module_function
6
7
 
7
8
  # Implement the {GraphQL::Tracing} API.
8
9
  def trace(key, metadata)
9
- push_data = case key
10
+ case key
10
11
  when "lex", "parse"
11
12
  # No context here, don't have a query yet
12
13
  nil
13
14
  when "execute_multiplex", "analyze_multiplex"
14
- metadata[:multiplex].queries
15
+ # No query context yet
16
+ nil
15
17
  when "validate", "analyze_query", "execute_query", "execute_query_lazy"
16
- metadata[:query] || metadata[:queries]
18
+ push_key = []
19
+ if (query = metadata[:query]) || ((queries = metadata[:queries]) && (query = queries.first))
20
+ push_data = query
21
+ multiplex = query.multiplex
22
+ elsif (multiplex = metadata[:multiplex])
23
+ push_data = multiplex.queries.first
24
+ end
17
25
  when "execute_field", "execute_field_lazy"
18
- metadata[:context]
26
+ query = metadata[:query]
27
+ multiplex = query.multiplex
28
+ push_key = metadata[:path]
29
+ parent_frame = multiplex.context[:graphql_backtrace_contexts][push_key[0..-2]]
30
+
31
+ if parent_frame.is_a?(GraphQL::Query)
32
+ parent_frame = parent_frame.context
33
+ end
34
+
35
+ push_data = Frame.new(
36
+ query: query,
37
+ path: push_key,
38
+ ast_node: metadata[:ast_node],
39
+ field: metadata[:field],
40
+ object: metadata[:object],
41
+ arguments: metadata[:arguments],
42
+ parent_frame: parent_frame,
43
+ )
19
44
  else
20
45
  # Custom key, no backtrace data for this
21
46
  nil
22
47
  end
23
48
 
24
- if push_data
25
- Thread.current[:last_graphql_backtrace_context] = push_data
49
+ if push_data && multiplex
50
+ push_storage = multiplex.context[:graphql_backtrace_contexts] ||= {}
51
+ push_storage[push_key] = push_data
52
+ multiplex.context[:last_graphql_backtrace_context] = push_data
26
53
  end
27
54
 
28
55
  if key == "execute_multiplex"
56
+ multiplex_context = metadata[:multiplex].context
29
57
  begin
30
58
  yield
31
59
  rescue StandardError => err
32
60
  # This is an unhandled error from execution,
33
61
  # Re-raise it with a GraphQL trace.
34
- potential_context = Thread.current[:last_graphql_backtrace_context]
62
+ potential_context = multiplex_context[:last_graphql_backtrace_context]
35
63
 
36
- if potential_context.is_a?(GraphQL::Query::Context) || potential_context.is_a?(GraphQL::Query::Context::FieldResolutionContext)
64
+ if potential_context.is_a?(GraphQL::Query::Context) ||
65
+ potential_context.is_a?(Backtrace::Frame)
37
66
  raise TracedError.new(err, potential_context)
38
67
  else
39
68
  raise
40
69
  end
41
70
  ensure
42
- Thread.current[:last_graphql_backtrace_context] = nil
71
+ multiplex_context.delete(:graphql_backtrace_contexts)
72
+ multiplex_context.delete(:last_graphql_backtrace_context)
43
73
  end
44
74
  else
45
75
  yield