graphql 2.6.12 → 2.6.14

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 (382) hide show
  1. checksums.yaml +4 -4
  2. data/.rdoc_options +4 -0
  3. data/lib/generators/graphql/core.rb +1 -0
  4. data/lib/generators/graphql/detailed_trace_generator.rb +1 -0
  5. data/lib/generators/graphql/enum_generator.rb +1 -0
  6. data/lib/generators/graphql/field_extractor.rb +1 -0
  7. data/lib/generators/graphql/input_generator.rb +1 -0
  8. data/lib/generators/graphql/install/mutation_root_generator.rb +1 -0
  9. data/lib/generators/graphql/install_generator.rb +1 -0
  10. data/lib/generators/graphql/interface_generator.rb +1 -0
  11. data/lib/generators/graphql/loader_generator.rb +8 -2
  12. data/lib/generators/graphql/mutation_create_generator.rb +8 -2
  13. data/lib/generators/graphql/mutation_delete_generator.rb +8 -2
  14. data/lib/generators/graphql/mutation_generator.rb +8 -2
  15. data/lib/generators/graphql/mutation_update_generator.rb +8 -2
  16. data/lib/generators/graphql/object_generator.rb +1 -0
  17. data/lib/generators/graphql/orm_mutations_base.rb +8 -2
  18. data/lib/generators/graphql/relay.rb +1 -0
  19. data/lib/generators/graphql/relay_generator.rb +1 -0
  20. data/lib/generators/graphql/scalar_generator.rb +1 -0
  21. data/lib/generators/graphql/type_generator.rb +38 -8
  22. data/lib/generators/graphql/union_generator.rb +1 -0
  23. data/lib/graphql/analysis/analyzer.rb +35 -9
  24. data/lib/graphql/analysis/field_usage.rb +1 -0
  25. data/lib/graphql/analysis/max_query_complexity.rb +3 -2
  26. data/lib/graphql/analysis/max_query_depth.rb +1 -0
  27. data/lib/graphql/analysis/query_complexity.rb +57 -20
  28. data/lib/graphql/analysis/query_depth.rb +17 -12
  29. data/lib/graphql/analysis/visitor.rb +79 -16
  30. data/lib/graphql/analysis.rb +23 -6
  31. data/lib/graphql/analysis_error.rb +1 -0
  32. data/lib/graphql/autoload.rb +30 -7
  33. data/lib/graphql/backtrace/table.rb +21 -5
  34. data/lib/graphql/backtrace/traced_error.rb +8 -3
  35. data/lib/graphql/backtrace.rb +14 -9
  36. data/lib/graphql/coercion_error.rb +1 -0
  37. data/lib/graphql/current.rb +44 -19
  38. data/lib/graphql/dashboard/application_controller.rb +1 -0
  39. data/lib/graphql/dashboard/detailed_traces.rb +1 -0
  40. data/lib/graphql/dashboard/installable.rb +1 -0
  41. data/lib/graphql/dashboard/landings_controller.rb +1 -0
  42. data/lib/graphql/dashboard/limiters.rb +1 -0
  43. data/lib/graphql/dashboard/operation_store.rb +1 -0
  44. data/lib/graphql/dashboard/statics_controller.rb +1 -0
  45. data/lib/graphql/dashboard/subscriptions.rb +1 -0
  46. data/lib/graphql/dashboard.rb +36 -22
  47. data/lib/graphql/dataloader/active_record_association_source.rb +1 -0
  48. data/lib/graphql/dataloader/active_record_source.rb +1 -0
  49. data/lib/graphql/dataloader/async_dataloader.rb +8 -7
  50. data/lib/graphql/dataloader/null_dataloader.rb +4 -3
  51. data/lib/graphql/dataloader/request.rb +8 -2
  52. data/lib/graphql/dataloader/request_all.rb +8 -2
  53. data/lib/graphql/dataloader/source.rb +127 -35
  54. data/lib/graphql/dataloader.rb +91 -42
  55. data/lib/graphql/date_encoding_error.rb +2 -1
  56. data/lib/graphql/dig.rb +12 -3
  57. data/lib/graphql/duration_encoding_error.rb +2 -1
  58. data/lib/graphql/execution/directive_checks.rb +8 -3
  59. data/lib/graphql/execution/errors.rb +20 -6
  60. data/lib/graphql/execution/field_resolve_step.rb +263 -161
  61. data/lib/graphql/execution/finalize.rb +12 -6
  62. data/lib/graphql/execution/input_values.rb +5 -2
  63. data/lib/graphql/execution/interpreter/argument_value.rb +17 -5
  64. data/lib/graphql/execution/interpreter/arguments.rb +24 -9
  65. data/lib/graphql/execution/interpreter/arguments_cache.rb +2 -1
  66. data/lib/graphql/execution/interpreter/execution_errors.rb +1 -0
  67. data/lib/graphql/execution/interpreter/handles_raw_value.rb +1 -0
  68. data/lib/graphql/execution/interpreter/resolve.rb +18 -8
  69. data/lib/graphql/execution/interpreter/runtime/graphql_result.rb +4 -1
  70. data/lib/graphql/execution/interpreter/runtime.rb +66 -23
  71. data/lib/graphql/execution/interpreter.rb +15 -6
  72. data/lib/graphql/execution/lazy/lazy_method_map.rb +21 -8
  73. data/lib/graphql/execution/lazy.rb +34 -10
  74. data/lib/graphql/execution/load_argument_step.rb +1 -0
  75. data/lib/graphql/execution/lookahead.rb +137 -54
  76. data/lib/graphql/execution/multiplex.rb +4 -4
  77. data/lib/graphql/execution/next.rb +7 -0
  78. data/lib/graphql/execution/prepare_object_step.rb +38 -13
  79. data/lib/graphql/execution/resolve_type_step.rb +2 -1
  80. data/lib/graphql/execution/runner.rb +9 -3
  81. data/lib/graphql/execution/selections_step.rb +3 -2
  82. data/lib/graphql/execution.rb +2 -2
  83. data/lib/graphql/execution_error.rb +19 -10
  84. data/lib/graphql/float_decoding_error.rb +1 -0
  85. data/lib/graphql/float_encoding_error.rb +7 -2
  86. data/lib/graphql/integer_decoding_error.rb +2 -1
  87. data/lib/graphql/integer_encoding_error.rb +8 -3
  88. data/lib/graphql/introspection/base_object.rb +3 -1
  89. data/lib/graphql/introspection/directive_location_enum.rb +1 -0
  90. data/lib/graphql/introspection/directive_type.rb +1 -0
  91. data/lib/graphql/introspection/dynamic_fields.rb +1 -0
  92. data/lib/graphql/introspection/entry_points.rb +1 -0
  93. data/lib/graphql/introspection/enum_value_type.rb +1 -0
  94. data/lib/graphql/introspection/field_type.rb +1 -0
  95. data/lib/graphql/introspection/input_value_type.rb +1 -0
  96. data/lib/graphql/introspection/introspection_query.rb +1 -0
  97. data/lib/graphql/introspection/schema_type.rb +1 -0
  98. data/lib/graphql/introspection/type_kind_enum.rb +1 -0
  99. data/lib/graphql/introspection/type_type.rb +1 -0
  100. data/lib/graphql/introspection.rb +1 -0
  101. data/lib/graphql/invalid_name_error.rb +1 -0
  102. data/lib/graphql/invalid_null_error.rb +19 -6
  103. data/lib/graphql/language/block_string.rb +2 -1
  104. data/lib/graphql/language/cache.rb +10 -4
  105. data/lib/graphql/language/comment.rb +1 -0
  106. data/lib/graphql/language/definition_slice.rb +1 -0
  107. data/lib/graphql/language/document_from_schema_definition.rb +9 -10
  108. data/lib/graphql/language/generation.rb +23 -9
  109. data/lib/graphql/language/lexer.rb +6 -1
  110. data/lib/graphql/language/nodes.rb +2094 -419
  111. data/lib/graphql/language/parser.rb +22 -12
  112. data/lib/graphql/language/printer.rb +31 -16
  113. data/lib/graphql/language/sanitized_printer.rb +16 -5
  114. data/lib/graphql/language/static_visitor.rb +19 -4
  115. data/lib/graphql/language/visitor.rb +51 -29
  116. data/lib/graphql/language.rb +13 -7
  117. data/lib/graphql/load_application_object_failed_error.rb +14 -5
  118. data/lib/graphql/name_validator.rb +1 -0
  119. data/lib/graphql/pagination/active_record_relation_connection.rb +1 -0
  120. data/lib/graphql/pagination/array_connection.rb +20 -6
  121. data/lib/graphql/pagination/connection.rb +178 -48
  122. data/lib/graphql/pagination/connections.rb +21 -14
  123. data/lib/graphql/pagination/mongoid_relation_connection.rb +1 -0
  124. data/lib/graphql/pagination/relation_connection.rb +137 -29
  125. data/lib/graphql/pagination/sequel_dataset_connection.rb +1 -0
  126. data/lib/graphql/pagination.rb +1 -0
  127. data/lib/graphql/parse_error.rb +1 -0
  128. data/lib/graphql/query/context/scoped_context.rb +2 -1
  129. data/lib/graphql/query/context.rb +106 -35
  130. data/lib/graphql/query/fingerprint.rb +15 -7
  131. data/lib/graphql/query/input_validation_result.rb +1 -0
  132. data/lib/graphql/query/null_context.rb +1 -0
  133. data/lib/graphql/query/partial.rb +28 -16
  134. data/lib/graphql/query/result.rb +15 -5
  135. data/lib/graphql/query/validation_pipeline.rb +16 -6
  136. data/lib/graphql/query/variable_validation_error.rb +1 -0
  137. data/lib/graphql/query/variables.rb +4 -1
  138. data/lib/graphql/query.rb +193 -49
  139. data/lib/graphql/railtie.rb +7 -3
  140. data/lib/graphql/rake_task/validate.rb +72 -17
  141. data/lib/graphql/rake_task.rb +55 -23
  142. data/lib/graphql/relay/range_add.rb +32 -21
  143. data/lib/graphql/relay.rb +1 -0
  144. data/lib/graphql/rubocop/graphql/base_cop.rb +1 -0
  145. data/lib/graphql/rubocop/graphql/default_null_true.rb +9 -6
  146. data/lib/graphql/rubocop/graphql/default_required_true.rb +9 -6
  147. data/lib/graphql/rubocop/graphql/field_type_in_block.rb +12 -8
  148. data/lib/graphql/rubocop/graphql/root_types_in_block.rb +9 -5
  149. data/lib/graphql/rubocop.rb +1 -0
  150. data/lib/graphql/runtime_error.rb +1 -0
  151. data/lib/graphql/runtime_type_error.rb +1 -0
  152. data/lib/graphql/schema/addition.rb +69 -50
  153. data/lib/graphql/schema/always_visible.rb +1 -0
  154. data/lib/graphql/schema/argument.rb +279 -45
  155. data/lib/graphql/schema/base_64_encoder.rb +2 -2
  156. data/lib/graphql/schema/build_from_definition/resolve_map/default_resolve.rb +1 -0
  157. data/lib/graphql/schema/build_from_definition/resolve_map.rb +2 -2
  158. data/lib/graphql/schema/build_from_definition.rb +507 -178
  159. data/lib/graphql/schema/built_in_types.rb +1 -0
  160. data/lib/graphql/schema/directive/deprecated.rb +1 -0
  161. data/lib/graphql/schema/directive/feature.rb +39 -22
  162. data/lib/graphql/schema/directive/flagged.rb +6 -1
  163. data/lib/graphql/schema/directive/include.rb +1 -0
  164. data/lib/graphql/schema/directive/one_of.rb +1 -0
  165. data/lib/graphql/schema/directive/skip.rb +1 -0
  166. data/lib/graphql/schema/directive/specified_by.rb +1 -0
  167. data/lib/graphql/schema/directive/transform.rb +17 -8
  168. data/lib/graphql/schema/directive.rb +28 -7
  169. data/lib/graphql/schema/enum.rb +99 -38
  170. data/lib/graphql/schema/enum_value.rb +21 -13
  171. data/lib/graphql/schema/field/connection_extension.rb +10 -2
  172. data/lib/graphql/schema/field/scope_extension.rb +1 -0
  173. data/lib/graphql/schema/field.rb +622 -110
  174. data/lib/graphql/schema/field_extension.rb +89 -34
  175. data/lib/graphql/schema/find_inherited_value.rb +5 -3
  176. data/lib/graphql/schema/finder.rb +22 -8
  177. data/lib/graphql/schema/has_single_input_argument.rb +39 -6
  178. data/lib/graphql/schema/input_object.rb +40 -13
  179. data/lib/graphql/schema/interface.rb +33 -17
  180. data/lib/graphql/schema/introspection_system.rb +7 -3
  181. data/lib/graphql/schema/late_bound_type.rb +2 -2
  182. data/lib/graphql/schema/list.rb +15 -4
  183. data/lib/graphql/schema/loader.rb +23 -12
  184. data/lib/graphql/schema/member/base_dsl_methods.rb +58 -12
  185. data/lib/graphql/schema/member/build_type.rb +21 -7
  186. data/lib/graphql/schema/member/graphql_type_names.rb +10 -6
  187. data/lib/graphql/schema/member/has_arguments.rb +111 -48
  188. data/lib/graphql/schema/member/has_ast_node.rb +1 -0
  189. data/lib/graphql/schema/member/has_authorization.rb +5 -0
  190. data/lib/graphql/schema/member/has_dataloader.rb +91 -34
  191. data/lib/graphql/schema/member/has_deprecation_reason.rb +15 -2
  192. data/lib/graphql/schema/member/has_directives.rb +45 -11
  193. data/lib/graphql/schema/member/has_fields.rb +151 -70
  194. data/lib/graphql/schema/member/has_interfaces.rb +8 -2
  195. data/lib/graphql/schema/member/has_path.rb +14 -5
  196. data/lib/graphql/schema/member/has_unresolved_type_error.rb +1 -0
  197. data/lib/graphql/schema/member/has_validators.rb +19 -4
  198. data/lib/graphql/schema/member/relay_shortcuts.rb +10 -2
  199. data/lib/graphql/schema/member/scoped.rb +14 -3
  200. data/lib/graphql/schema/member/type_system_helpers.rb +36 -6
  201. data/lib/graphql/schema/member/validates_input.rb +1 -0
  202. data/lib/graphql/schema/member.rb +9 -2
  203. data/lib/graphql/schema/mutation.rb +50 -46
  204. data/lib/graphql/schema/non_null.rb +21 -5
  205. data/lib/graphql/schema/object.rb +44 -15
  206. data/lib/graphql/schema/printer.rb +52 -31
  207. data/lib/graphql/schema/ractor_shareable.rb +6 -2
  208. data/lib/graphql/schema/relay_classic_mutation.rb +3 -3
  209. data/lib/graphql/schema/resolver/has_payload_type.rb +29 -7
  210. data/lib/graphql/schema/resolver.rb +156 -45
  211. data/lib/graphql/schema/scalar.rb +1 -0
  212. data/lib/graphql/schema/subscription.rb +67 -28
  213. data/lib/graphql/schema/timeout.rb +65 -25
  214. data/lib/graphql/schema/type_expression.rb +14 -5
  215. data/lib/graphql/schema/type_membership.rb +29 -10
  216. data/lib/graphql/schema/union.rb +4 -2
  217. data/lib/graphql/schema/unique_within_type.rb +24 -5
  218. data/lib/graphql/schema/validator/all_validator.rb +17 -9
  219. data/lib/graphql/schema/validator/allow_blank_validator.rb +8 -2
  220. data/lib/graphql/schema/validator/allow_null_validator.rb +8 -2
  221. data/lib/graphql/schema/validator/exclusion_validator.rb +14 -5
  222. data/lib/graphql/schema/validator/format_validator.rb +21 -10
  223. data/lib/graphql/schema/validator/inclusion_validator.rb +15 -6
  224. data/lib/graphql/schema/validator/length_validator.rb +23 -12
  225. data/lib/graphql/schema/validator/numericality_validator.rb +29 -16
  226. data/lib/graphql/schema/validator/required_validator.rb +45 -31
  227. data/lib/graphql/schema/validator.rb +89 -25
  228. data/lib/graphql/schema/visibility/migration.rb +14 -7
  229. data/lib/graphql/schema/visibility/profile.rb +20 -17
  230. data/lib/graphql/schema/visibility/visit.rb +12 -10
  231. data/lib/graphql/schema/visibility.rb +24 -20
  232. data/lib/graphql/schema/warden.rb +117 -31
  233. data/lib/graphql/schema/wrapper.rb +4 -1
  234. data/lib/graphql/schema.rb +1050 -302
  235. data/lib/graphql/static_validation/all_rules.rb +2 -1
  236. data/lib/graphql/static_validation/base_visitor.rb +48 -8
  237. data/lib/graphql/static_validation/definition_dependencies.rb +27 -7
  238. data/lib/graphql/static_validation/error.rb +3 -0
  239. data/lib/graphql/static_validation/interpreter_visitor.rb +1 -0
  240. data/lib/graphql/static_validation/literal_validator.rb +1 -0
  241. data/lib/graphql/static_validation/rules/argument_literals_are_compatible.rb +4 -0
  242. data/lib/graphql/static_validation/rules/argument_literals_are_compatible_error.rb +1 -0
  243. data/lib/graphql/static_validation/rules/argument_names_are_unique.rb +3 -0
  244. data/lib/graphql/static_validation/rules/argument_names_are_unique_error.rb +1 -0
  245. data/lib/graphql/static_validation/rules/arguments_are_defined.rb +3 -0
  246. data/lib/graphql/static_validation/rules/arguments_are_defined_error.rb +1 -0
  247. data/lib/graphql/static_validation/rules/directives_are_defined.rb +3 -0
  248. data/lib/graphql/static_validation/rules/directives_are_defined_error.rb +1 -0
  249. data/lib/graphql/static_validation/rules/directives_are_in_valid_locations.rb +3 -0
  250. data/lib/graphql/static_validation/rules/directives_are_in_valid_locations_error.rb +1 -0
  251. data/lib/graphql/static_validation/rules/fields_are_defined_on_type.rb +3 -0
  252. data/lib/graphql/static_validation/rules/fields_are_defined_on_type_error.rb +1 -0
  253. data/lib/graphql/static_validation/rules/fields_have_appropriate_selections.rb +9 -1
  254. data/lib/graphql/static_validation/rules/fields_have_appropriate_selections_error.rb +1 -0
  255. data/lib/graphql/static_validation/rules/fields_will_merge.rb +295 -134
  256. data/lib/graphql/static_validation/rules/fields_will_merge_error.rb +14 -2
  257. data/lib/graphql/static_validation/rules/fragment_names_are_unique.rb +3 -0
  258. data/lib/graphql/static_validation/rules/fragment_names_are_unique_error.rb +1 -0
  259. data/lib/graphql/static_validation/rules/fragment_spreads_are_possible.rb +3 -0
  260. data/lib/graphql/static_validation/rules/fragment_spreads_are_possible_error.rb +1 -0
  261. data/lib/graphql/static_validation/rules/fragment_types_exist.rb +3 -0
  262. data/lib/graphql/static_validation/rules/fragment_types_exist_error.rb +1 -0
  263. data/lib/graphql/static_validation/rules/fragments_are_finite.rb +3 -0
  264. data/lib/graphql/static_validation/rules/fragments_are_finite_error.rb +1 -0
  265. data/lib/graphql/static_validation/rules/fragments_are_named.rb +3 -0
  266. data/lib/graphql/static_validation/rules/fragments_are_named_error.rb +1 -0
  267. data/lib/graphql/static_validation/rules/fragments_are_on_composite_types.rb +3 -0
  268. data/lib/graphql/static_validation/rules/fragments_are_on_composite_types_error.rb +1 -0
  269. data/lib/graphql/static_validation/rules/fragments_are_used.rb +3 -0
  270. data/lib/graphql/static_validation/rules/fragments_are_used_error.rb +1 -0
  271. data/lib/graphql/static_validation/rules/input_object_names_are_unique.rb +3 -0
  272. data/lib/graphql/static_validation/rules/input_object_names_are_unique_error.rb +1 -0
  273. data/lib/graphql/static_validation/rules/mutation_root_exists.rb +3 -0
  274. data/lib/graphql/static_validation/rules/mutation_root_exists_error.rb +1 -0
  275. data/lib/graphql/static_validation/rules/no_definitions_are_present.rb +3 -0
  276. data/lib/graphql/static_validation/rules/no_definitions_are_present_error.rb +1 -0
  277. data/lib/graphql/static_validation/rules/not_single_subscription_error.rb +1 -0
  278. data/lib/graphql/static_validation/rules/one_of_input_objects_are_valid.rb +4 -0
  279. data/lib/graphql/static_validation/rules/one_of_input_objects_are_valid_error.rb +1 -0
  280. data/lib/graphql/static_validation/rules/operation_names_are_valid.rb +3 -0
  281. data/lib/graphql/static_validation/rules/operation_names_are_valid_error.rb +1 -0
  282. data/lib/graphql/static_validation/rules/query_root_exists.rb +3 -0
  283. data/lib/graphql/static_validation/rules/query_root_exists_error.rb +1 -0
  284. data/lib/graphql/static_validation/rules/required_arguments_are_present.rb +4 -1
  285. data/lib/graphql/static_validation/rules/required_arguments_are_present_error.rb +1 -0
  286. data/lib/graphql/static_validation/rules/required_input_object_attributes_are_present.rb +4 -0
  287. data/lib/graphql/static_validation/rules/required_input_object_attributes_are_present_error.rb +1 -0
  288. data/lib/graphql/static_validation/rules/subscription_root_exists_and_single_subscription_selection.rb +4 -1
  289. data/lib/graphql/static_validation/rules/subscription_root_exists_error.rb +1 -0
  290. data/lib/graphql/static_validation/rules/unique_directives_per_location.rb +3 -0
  291. data/lib/graphql/static_validation/rules/unique_directives_per_location_error.rb +1 -0
  292. data/lib/graphql/static_validation/rules/variable_default_values_are_correctly_typed.rb +3 -0
  293. data/lib/graphql/static_validation/rules/variable_default_values_are_correctly_typed_error.rb +1 -0
  294. data/lib/graphql/static_validation/rules/variable_names_are_unique.rb +3 -0
  295. data/lib/graphql/static_validation/rules/variable_names_are_unique_error.rb +1 -0
  296. data/lib/graphql/static_validation/rules/variable_usages_are_allowed.rb +207 -51
  297. data/lib/graphql/static_validation/rules/variable_usages_are_allowed_error.rb +1 -0
  298. data/lib/graphql/static_validation/rules/variables_are_input_types.rb +3 -0
  299. data/lib/graphql/static_validation/rules/variables_are_input_types_error.rb +1 -0
  300. data/lib/graphql/static_validation/rules/variables_are_used_and_defined.rb +6 -3
  301. data/lib/graphql/static_validation/rules/variables_are_used_and_defined_error.rb +1 -0
  302. data/lib/graphql/static_validation/validation_context.rb +3 -2
  303. data/lib/graphql/static_validation/validation_timeout_error.rb +1 -0
  304. data/lib/graphql/static_validation/validator.rb +41 -16
  305. data/lib/graphql/static_validation.rb +1 -0
  306. data/lib/graphql/string_encoding_error.rb +1 -0
  307. data/lib/graphql/subscriptions/action_cable_subscriptions.rb +85 -65
  308. data/lib/graphql/subscriptions/broadcast_analyzer.rb +10 -4
  309. data/lib/graphql/subscriptions/default_subscription_resolve_extension.rb +1 -0
  310. data/lib/graphql/subscriptions/event.rb +25 -6
  311. data/lib/graphql/subscriptions/serialize.rb +58 -19
  312. data/lib/graphql/subscriptions.rb +172 -46
  313. data/lib/graphql/testing/helpers.rb +17 -4
  314. data/lib/graphql/testing/mock_action_cable.rb +55 -33
  315. data/lib/graphql/testing.rb +1 -0
  316. data/lib/graphql/tracing/active_support_notifications_trace.rb +17 -9
  317. data/lib/graphql/tracing/active_support_notifications_tracing.rb +2 -1
  318. data/lib/graphql/tracing/appoptics_trace.rb +2 -1
  319. data/lib/graphql/tracing/appoptics_tracing.rb +2 -1
  320. data/lib/graphql/tracing/appsignal_trace.rb +16 -7
  321. data/lib/graphql/tracing/appsignal_tracing.rb +7 -3
  322. data/lib/graphql/tracing/call_legacy_tracers.rb +1 -0
  323. data/lib/graphql/tracing/data_dog_trace.rb +17 -6
  324. data/lib/graphql/tracing/data_dog_tracing.rb +10 -3
  325. data/lib/graphql/tracing/detailed_trace/active_record_backend.rb +1 -0
  326. data/lib/graphql/tracing/detailed_trace/memory_backend.rb +1 -0
  327. data/lib/graphql/tracing/detailed_trace/redis_backend.rb +1 -0
  328. data/lib/graphql/tracing/detailed_trace.rb +105 -42
  329. data/lib/graphql/tracing/legacy_hooks_trace.rb +5 -0
  330. data/lib/graphql/tracing/legacy_trace.rb +1 -0
  331. data/lib/graphql/tracing/monitor_trace.rb +17 -11
  332. data/lib/graphql/tracing/new_relic_trace.rb +17 -8
  333. data/lib/graphql/tracing/new_relic_tracing.rb +7 -3
  334. data/lib/graphql/tracing/notifications_trace.rb +11 -8
  335. data/lib/graphql/tracing/notifications_tracing.rb +23 -7
  336. data/lib/graphql/tracing/null_trace.rb +1 -0
  337. data/lib/graphql/tracing/perfetto_trace/trace_pb.rb +1 -0
  338. data/lib/graphql/tracing/perfetto_trace.rb +41 -19
  339. data/lib/graphql/tracing/platform_trace.rb +3 -1
  340. data/lib/graphql/tracing/platform_tracing.rb +16 -7
  341. data/lib/graphql/tracing/prometheus_trace/graphql_collector.rb +1 -0
  342. data/lib/graphql/tracing/prometheus_trace.rb +22 -13
  343. data/lib/graphql/tracing/prometheus_tracing.rb +1 -0
  344. data/lib/graphql/tracing/scout_trace.rb +10 -4
  345. data/lib/graphql/tracing/scout_tracing.rb +7 -3
  346. data/lib/graphql/tracing/sentry_trace.rb +12 -5
  347. data/lib/graphql/tracing/statsd_trace.rb +12 -6
  348. data/lib/graphql/tracing/statsd_tracing.rb +7 -1
  349. data/lib/graphql/tracing/trace.rb +231 -58
  350. data/lib/graphql/tracing.rb +25 -9
  351. data/lib/graphql/type_kinds.rb +2 -1
  352. data/lib/graphql/types/big_int.rb +1 -0
  353. data/lib/graphql/types/boolean.rb +1 -0
  354. data/lib/graphql/types/float.rb +1 -0
  355. data/lib/graphql/types/id.rb +1 -0
  356. data/lib/graphql/types/int.rb +2 -1
  357. data/lib/graphql/types/iso_8601_date.rb +21 -4
  358. data/lib/graphql/types/iso_8601_date_time.rb +33 -6
  359. data/lib/graphql/types/iso_8601_duration.rb +42 -9
  360. data/lib/graphql/types/json.rb +1 -0
  361. data/lib/graphql/types/relay/base_connection.rb +38 -32
  362. data/lib/graphql/types/relay/base_edge.rb +15 -9
  363. data/lib/graphql/types/relay/connection_behaviors.rb +19 -3
  364. data/lib/graphql/types/relay/edge_behaviors.rb +17 -4
  365. data/lib/graphql/types/relay/has_node_field.rb +6 -1
  366. data/lib/graphql/types/relay/has_nodes_field.rb +6 -1
  367. data/lib/graphql/types/relay/node.rb +1 -0
  368. data/lib/graphql/types/relay/node_behaviors.rb +5 -1
  369. data/lib/graphql/types/relay/page_info.rb +1 -0
  370. data/lib/graphql/types/relay/page_info_behaviors.rb +1 -0
  371. data/lib/graphql/types/relay.rb +4 -3
  372. data/lib/graphql/types/string.rb +1 -0
  373. data/lib/graphql/types.rb +1 -0
  374. data/lib/graphql/unauthorized_enum_value_error.rb +4 -1
  375. data/lib/graphql/unauthorized_error.rb +11 -4
  376. data/lib/graphql/unauthorized_field_error.rb +4 -1
  377. data/lib/graphql/unresolved_type_error.rb +16 -5
  378. data/lib/graphql/version.rb +2 -1
  379. data/lib/graphql.rb +37 -9
  380. data/readme.md +1 -1
  381. metadata +89 -5
  382. data/.yardopts +0 -5
data/lib/graphql/dig.rb CHANGED
@@ -1,13 +1,22 @@
1
1
  # frozen_string_literal: true
2
+ # typed: true
2
3
  module GraphQL
3
4
  module Dig
4
5
  # implemented using the old activesupport #dig instead of the ruby built-in
5
6
  # so we can use some of the magic in Schema::InputObject and Interpreter::Arguments
6
7
  # to handle stringified/symbolized keys.
7
8
  #
8
- # @param own_key [String, Symbol] A key to retrieve
9
- # @param rest_keys [Array<[String, Symbol>] Retrieves the value object corresponding to the each key objects repeatedly
10
- # @return [Object]
9
+ # **Parameters**
10
+ #
11
+ # - `own_key` (`String, Symbol`) — A key to retrieve
12
+ # - `rest_keys` (`Array<[String, Symbol]>`) — Keys to use for retrieving nested values
13
+ #
14
+ # **Returns**
15
+ #
16
+ # - `Object`
17
+ #
18
+ # :call-seq:
19
+ # dig(String | Symbol own_key, Array[[String, Symbol]] *rest_keys) -> Object
11
20
  def dig(own_key, *rest_keys)
12
21
  val = self[own_key]
13
22
  if val.nil? || rest_keys.empty?
@@ -1,9 +1,10 @@
1
1
  # frozen_string_literal: true
2
+ # typed: true
2
3
  module GraphQL
3
4
  # This error is raised when `Types::ISO8601Duration` is asked to return a value
4
5
  # that cannot be parsed as an ISO8601-formatted duration by ActiveSupport::Duration.
5
6
  #
6
- # @see GraphQL::Types::ISO8601Duration which raises this error
7
+ # See [GraphQL::Types::ISO8601Duration](rdoc-ref:GraphQL::Types::ISO8601Duration) which raises this error
7
8
  class DurationEncodingError < GraphQL::RuntimeTypeError
8
9
  # The value which couldn't be encoded
9
10
  attr_reader :duration_value
@@ -1,16 +1,21 @@
1
1
  # frozen_string_literal: true
2
+ # typed: true
2
3
  module GraphQL
3
4
  module Execution
4
5
  # Boolean checks for how an AST node's directives should
5
6
  # influence its execution
6
- # @api private
7
- module DirectiveChecks
7
+ module DirectiveChecks # :nodoc:
8
8
  SKIP = "skip"
9
9
  INCLUDE = "include"
10
10
 
11
11
  module_function
12
12
 
13
- # @return [Boolean] Should this node be included in the query?
13
+ # **Returns**
14
+ #
15
+ # - `Boolean` — Should this node be included in the query?
16
+ #
17
+ # :call-seq:
18
+ # include?(directive_ast_nodes, query) -> bool
14
19
  def include?(directive_ast_nodes, query)
15
20
  directive_ast_nodes.each do |directive_ast_node|
16
21
  name = directive_ast_node.name
@@ -1,4 +1,5 @@
1
1
  # frozen_string_literal: true
2
+ # typed: true
2
3
 
3
4
  module GraphQL
4
5
  module Execution
@@ -6,10 +7,18 @@ module GraphQL
6
7
  # Register this handler, updating the
7
8
  # internal handler index to maintain least-to-most specific.
8
9
  #
9
- # @param error_class [Class<Exception>]
10
- # @param error_handlers [Hash]
11
- # @param error_handler [Proc]
12
- # @return [void]
10
+ # **Parameters**
11
+ #
12
+ # - `error_class` (`Class<Exception>`)
13
+ # - `error_handlers` (`Hash`)
14
+ # - `error_handler` (`Proc`)
15
+ #
16
+ # **Returns**
17
+ #
18
+ # - `void`
19
+ #
20
+ # :call-seq:
21
+ # register_rescue_from(Class[Exception] error_class, Hash error_handlers, Proc error_handler) -> void
13
22
  def self.register_rescue_from(error_class, error_handlers, error_handler)
14
23
  subclasses_handlers = {}
15
24
  this_level_subclasses = []
@@ -52,10 +61,15 @@ module GraphQL
52
61
  nil
53
62
  end
54
63
 
55
- # @return [Proc, nil] The handler for `error_class`, if one was registered on this schema or inherited
64
+ # **Returns**
65
+ #
66
+ # - `Proc, nil` — The handler for `error_class`, if one was registered on this schema or inherited
67
+ #
68
+ # :call-seq:
69
+ # find_handler_for(schema, error_class) -> Proc | nil
56
70
  def self.find_handler_for(schema, error_class)
57
71
  handlers = schema.error_handlers[:subclass_handlers]
58
- handler = nil
72
+ handler = nil #: untyped
59
73
  while (handlers) do
60
74
  _err_class, next_handler = handlers.find { |err_class, handler| error_class <= err_class }
61
75
  if next_handler
@@ -1,4 +1,5 @@
1
1
  # frozen_string_literal: true
2
+ # typed: true
2
3
  module GraphQL
3
4
  module Execution
4
5
  class FieldResolveStep
@@ -25,6 +26,8 @@ module GraphQL
25
26
  @finish_extension_idx = nil
26
27
  @was_scoped = nil
27
28
  @pending_steps = nil
29
+ @field_authorization_objects = @field_authorization_results = @field_authorization_errors = nil
30
+ @field_authorization_next_idx = @field_authorization_pending = nil
28
31
  @arguments_without_loads = @post_processors = @directive_finalizers = nil
29
32
  end
30
33
 
@@ -93,6 +96,12 @@ module GraphQL
93
96
  finish_extensions
94
97
  elsif @field_results
95
98
  build_results
99
+ elsif @field_authorization_results
100
+ if @field_authorization_next_idx < @field_authorization_objects.size
101
+ authorize_next_field_object
102
+ else
103
+ finish_field_authorizations
104
+ end
96
105
  elsif @arguments
97
106
  execute_field
98
107
  else
@@ -117,7 +126,7 @@ module GraphQL
117
126
  @runner.add_finalizer(@selections_step.query, result, key, err)
118
127
  if !err.is_a?(GraphQL::Execution::Skip)
119
128
  field_type = return_type
120
- should_propagate_null = field_type.non_null?
129
+ should_propagate_null = field_type.non_null? #: bool
121
130
  while (should_propagate_null == false && field_type.kind.wraps?)
122
131
  field_type = field_type.of_type
123
132
  should_propagate_null = field_type.non_null?
@@ -130,10 +139,10 @@ module GraphQL
130
139
  end
131
140
 
132
141
  def propagate_nulls
133
- propagating_null = true
142
+ propagating_null = true #: bool
134
143
  highest_nulled_depth = path.size
135
- highest_list_depth = nil
136
- current_field_step = self
144
+ highest_list_depth = nil #: Integer?
145
+ current_field_step = self #: FieldResolveStep?
137
146
  while current_field_step && current_field_step.field_definition
138
147
  return_type = current_field_step.field_definition.type
139
148
  if propagating_null && return_type.non_null?
@@ -150,7 +159,7 @@ module GraphQL
150
159
  end
151
160
 
152
161
  if highest_list_depth.nil? || highest_nulled_depth <= highest_list_depth
153
- kill_field_step = self
162
+ kill_field_step = self #: FieldResolveStep?
154
163
  while kill_field_step && kill_field_step.field_definition && highest_nulled_depth <= kill_field_step.path.size
155
164
  kill_field_step.selections_step.killed = true
156
165
  kill_field_step = kill_field_step.selections_step.field_resolve_step
@@ -242,153 +251,30 @@ module GraphQL
242
251
  end
243
252
 
244
253
  if @runner.authorizes?(@field_definition, ctx)
245
- authorized_objects = []
246
- authorized_results = []
247
- l = objects.size
248
- i = 0
249
- while i < l
250
- o = objects[i]
251
- err = nil
252
- begin
253
- field_authed = @field_definition.authorized?(o, @arguments, ctx)
254
- if @runner.resolves_lazies && @runner.lazy?(field_authed)
255
- # TODO batch this properly...
256
- field_authed = sync(field_authed)
257
- end
258
- rescue GraphQL::UnauthorizedFieldError => field_auth_err
259
- err = field_auth_err
260
- err.field ||= @field_definition
261
- field_authed = false
262
- end
263
-
264
- if field_authed
265
- authorized_results << @results[i]
266
- authorized_objects << o
267
- else
268
- begin
269
- err ||= GraphQL::UnauthorizedFieldError.new(object: o, type: @parent_type, context: ctx, field: @field_definition)
270
- new_obj = query.schema.unauthorized_field(err)
271
- if !new_obj.nil?
272
- authorized_objects << new_obj
273
- authorized_results << @results[i]
274
- end
275
- rescue GraphQL::ExecutionError => exec_err
276
- add_graphql_error(@results[i], key, exec_err)
277
- end
278
- end
279
- i += 1
280
- end
281
-
282
- if authorized_objects.size == 0
254
+ @field_authorization_objects = objects
255
+ @field_authorization_results = Array.new(objects.size)
256
+ @field_authorization_next_idx = 0
257
+ if objects.size > 1 && !@runner.dataloader.is_a?(GraphQL::Dataloader::NullDataloader)
258
+ # Enqueue this step once per object, so Dataloader sources loaded by `authorized?` batch across objects.
259
+ # Each call authorizes the next object; see `authorize_next_field_object`.
260
+ @field_authorization_pending = objects.size
261
+ objects.size.times { @runner.dataloader.append_job(self) }
283
262
  return
284
263
  end
285
- @results = authorized_results
264
+ objects.size.times { |idx| authorize_field_at(idx, ctx) }
265
+ authorized_objects = collect_field_authorizations
266
+ return if authorized_objects.nil?
286
267
  else
287
268
  authorized_objects = objects
288
269
  end
289
270
 
290
- if @parent_type.default_relay? && SCOPED_RELAY_FIELD_NAMES.include?(@field_definition.original_name) && authorized_objects.all? { |o| o.respond_to?(:was_authorized_by_scope_items?) && o.was_authorized_by_scope_items? }
291
- @was_scoped = true
292
- end
293
-
294
- query.current_trace.begin_execute_field(@field_definition, authorized_objects, @arguments, query)
295
-
296
- if @runner.uses_runtime_directives
297
- if @ast_nodes.nil? || @ast_nodes.size == 1
298
- directives = if !@ast_node.directives.empty?
299
- @ast_node.directives
300
- else
301
- nil
302
- end
303
- else
304
- directives = nil
305
- @ast_nodes.each do |n|
306
- if (d = n.directives).any? # rubocop:disable Development/NoneWithoutBlockCop
307
- directives ||= []
308
- directives.concat(d)
309
- end
310
- end
311
- end
312
-
313
- if directives
314
- directives.each do |dir_node|
315
- if (dir_defn = @runner.runtime_directives[dir_node.name])
316
- dir_args, errors = @runner.input_values[query].argument_values(dir_defn, dir_node.arguments, self) # rubocop:disable Development/ContextIsPassedCop
317
- if errors
318
- @results.each { |r| r.delete(@key) }
319
- errors.each { |e| e.ast_node = dir_node }
320
- build_errors_result(errors, nil)
321
- return
322
- else
323
- begin
324
- dir_defn.validate!(dir_args, query.context)
325
- if !(result = dir_defn.resolve_field(ast_nodes, @parent_type, field_definition, authorized_objects, dir_args, ctx)).nil?
326
- if result.is_a?(Finalizer)
327
- result.path = path
328
- @directive_finalizers ||= []
329
- @directive_finalizers << result
330
- end
331
-
332
- if result.is_a?(PostProcessor)
333
- @post_processors ||= []
334
- @post_processors << result
335
- end
336
-
337
- if result.is_a?(HaltExecution)
338
- @directive_finalizers&.each { |f|
339
- @selections_step.results.each { |r| @runner.add_finalizer(query, r, key, f) }
340
- }
341
- return
342
- end
343
- end
344
- rescue GraphQL::RuntimeError => err
345
- err.ast_node = dir_node
346
- raise
347
- end
348
- end
349
- end
350
- end
351
- end
352
- end
353
-
354
- has_extensions = @field_definition.extensions.size > 0
355
- if has_extensions
356
- @extended = GraphQL::Schema::Field::ExtendedState.new(@arguments, authorized_objects)
357
- @field_results = @field_definition.run_next_extensions_before_resolve(authorized_objects, @arguments, ctx, @extended) do |objs, args|
358
- if (added_extras = @extended.added_extras)
359
- args = args.dup
360
- added_extras.each { |e| args.delete(e) }
361
- end
362
- resolve_batch(objs, ctx, args)
363
- end
364
- @finish_extension_idx = 0
365
- else
366
- @field_results = resolve_batch(authorized_objects, ctx, @arguments)
367
- end
368
-
369
- query.current_trace.end_execute_field(@field_definition, authorized_objects, @arguments, query, @field_results)
370
-
371
- if any_lazy_results?
372
- @runner.dataloader.lazy_at_depth(path.size, self)
373
- elsif @pending_steps.nil? || @pending_steps.empty?
374
- if has_extensions
375
- finish_extensions
376
- else
377
- build_results
378
- end
379
- end
380
- rescue GraphQL::ExecutionError => err
381
- build_errors_result(nil, err)
382
- rescue StandardError => stderr
383
- begin
384
- @selections_step.query.handle_or_reraise(stderr, field: @field_definition, arguments: @arguments, object: nil)
385
- rescue GraphQL::ExecutionError => err
386
- add_graphql_error(@results[0], key, err)
387
- end
271
+ execute_authorized_field(authorized_objects)
272
+ rescue StandardError => err
273
+ handle_execute_field_error(err)
388
274
  end
389
275
 
390
276
  def any_lazy_results?
391
- lazies = false
277
+ lazies = false #: bool
392
278
  if @runner.resolves_lazies # TODO extract this
393
279
  @field_results.each do |field_result|
394
280
  if @runner.lazy?(field_result)
@@ -418,11 +304,15 @@ module GraphQL
418
304
  case ext
419
305
  when Schema::Field::ConnectionExtension
420
306
  conns = ctx.schema.connections
307
+ lookahead = @arguments[:lookahead]
308
+ # The memo omits the extension's extras (`:lookahead`)
309
+ conn_arguments = memos[@finish_extension_idx] || @arguments
421
310
  @field_results.map!.each_with_index do |value, idx|
422
311
  object = @extended.object[idx]
423
- conn = conns.populate_connection(@field_definition, object, value, @arguments, ctx)
312
+ conn = conns.populate_connection(@field_definition, object, value, conn_arguments, ctx)
424
313
  if conn
425
314
  conn.was_authorized_by_scope_items = @was_scoped
315
+ conn.lookahead ||= lookahead
426
316
  end
427
317
  conn
428
318
  rescue GraphQL::RuntimeError => err
@@ -514,7 +404,7 @@ module GraphQL
514
404
  def build_leaf_result(result_h, result_key, field_result, return_type, ctx, is_from_array)
515
405
  if field_result.nil?
516
406
  if return_type.non_null?
517
- add_non_null_error(is_from_array)
407
+ add_non_null_error(is_from_array, return_type: return_type)
518
408
  else
519
409
  nil
520
410
  end
@@ -609,8 +499,14 @@ module GraphQL
609
499
  end
610
500
  end
611
501
 
612
- def add_non_null_error(is_from_array)
613
- err = @parent_type::InvalidNullError.new(@parent_type, @field_definition, ast_nodes, is_from_array: is_from_array, path: path)
502
+ def add_non_null_error(is_from_array, return_type: nil)
503
+ if is_from_array && return_type
504
+ list_type = @field_definition.type
505
+ list_type = list_type.of_type if list_type.non_null?
506
+ # Preserve existing messages for single-level lists.
507
+ element_type = return_type.of_type if list_type.of_type.list?
508
+ end
509
+ err = @parent_type.const_get(:InvalidNullError).new(@parent_type, @field_definition, ast_nodes, is_from_array: is_from_array, path: path, element_type: element_type)
614
510
  nn_result = @runner.schema.type_error(err, @selections_step.query.context)
615
511
  if nn_result.nil?
616
512
  propagate_nulls
@@ -624,6 +520,207 @@ module GraphQL
624
520
 
625
521
  private
626
522
 
523
+ def execute_authorized_field(authorized_objects)
524
+ query = @selections_step.query
525
+ ctx = query.context
526
+
527
+ if @parent_type.default_relay? && SCOPED_RELAY_FIELD_NAMES.include?(@field_definition.original_name) && authorized_objects.all? { |o| o.respond_to?(:was_authorized_by_scope_items?) && o.was_authorized_by_scope_items? }
528
+ @was_scoped = true
529
+ end
530
+
531
+ query.current_trace.begin_execute_field(@field_definition, authorized_objects, @arguments, query)
532
+
533
+ if @runner.uses_runtime_directives
534
+ if @ast_nodes.nil? || @ast_nodes.size == 1
535
+ directives = if !@ast_node.directives.empty?
536
+ @ast_node.directives
537
+ else
538
+ nil
539
+ end
540
+ else
541
+ directives = nil #: Array[untyped]?
542
+ @ast_nodes.each do |n|
543
+ if (d = n.directives).any? # rubocop:disable Development/NoneWithoutBlockCop
544
+ directives ||= []
545
+ directives.concat(d)
546
+ end
547
+ end
548
+ end
549
+
550
+ if directives
551
+ directives.each do |dir_node|
552
+ if (dir_defn = @runner.runtime_directives[dir_node.name])
553
+ dir_args, errors = @runner.input_values[query].argument_values(dir_defn, dir_node.arguments, self) # rubocop:disable Development/ContextIsPassedCop
554
+ if errors
555
+ @results.each { |r| r.delete(@key) }
556
+ errors.each { |e| e.ast_node = dir_node }
557
+ build_errors_result(errors, nil)
558
+ return
559
+ else
560
+ begin
561
+ dir_defn.validate!(dir_args, query.context)
562
+ if !(result = dir_defn.resolve_field(ast_nodes, @parent_type, field_definition, authorized_objects, dir_args, ctx)).nil?
563
+ if result.is_a?(Finalizer)
564
+ result.path = path
565
+ @directive_finalizers ||= []
566
+ @directive_finalizers << result
567
+ end
568
+
569
+ if result.is_a?(PostProcessor)
570
+ @post_processors ||= []
571
+ @post_processors << result
572
+ end
573
+
574
+ if result.is_a?(HaltExecution)
575
+ @directive_finalizers&.each { |f|
576
+ @selections_step.results.each { |r| @runner.add_finalizer(query, r, key, f) }
577
+ }
578
+ return
579
+ end
580
+ end
581
+ rescue GraphQL::RuntimeError => err
582
+ err.ast_node = dir_node
583
+ raise
584
+ end
585
+ end
586
+ end
587
+ end
588
+ end
589
+ end
590
+
591
+ has_extensions = @field_definition.extensions.size > 0
592
+ if has_extensions
593
+ @extended = GraphQL::Schema::Field::ExtendedState.new(@arguments, authorized_objects)
594
+ @field_results = @field_definition.run_next_extensions_before_resolve(authorized_objects, @arguments, ctx, @extended) do |objs, args|
595
+ if (added_extras = @extended.added_extras)
596
+ args = args.dup
597
+ added_extras.each { |e| args.delete(e) }
598
+ end
599
+ resolve_batch(objs, ctx, args)
600
+ end
601
+ @finish_extension_idx = 0
602
+ else
603
+ @field_results = resolve_batch(authorized_objects, ctx, @arguments)
604
+ end
605
+
606
+ query.current_trace.end_execute_field(@field_definition, authorized_objects, @arguments, query, @field_results)
607
+
608
+ if any_lazy_results?
609
+ @runner.dataloader.lazy_at_depth(path.size, self)
610
+ elsif @pending_steps.nil? || @pending_steps.empty?
611
+ if has_extensions
612
+ finish_extensions
613
+ else
614
+ build_results
615
+ end
616
+ end
617
+ rescue StandardError => err
618
+ handle_execute_field_error(err)
619
+ end
620
+
621
+ def handle_execute_field_error(err)
622
+ if @field_authorization_objects
623
+ clear_field_authorizations
624
+ end
625
+ if err.is_a?(GraphQL::ExecutionError)
626
+ build_errors_result(nil, err)
627
+ else
628
+ begin
629
+ @selections_step.query.handle_or_reraise(err, field: @field_definition, arguments: @arguments, object: nil)
630
+ rescue GraphQL::ExecutionError => exec_err
631
+ add_graphql_error(@results[0], key, exec_err)
632
+ end
633
+ end
634
+ end
635
+
636
+ # Stores the (possibly synced) +authorized?+ result for the object at +idx+.
637
+ # A GraphQL::UnauthorizedFieldError raised by +authorized?+ is stored in +@field_authorization_errors+.
638
+ def authorize_field_at(idx, ctx)
639
+ field_authed = @field_definition.authorized?(@field_authorization_objects[idx], @arguments, ctx)
640
+ if @runner.resolves_lazies && @runner.lazy?(field_authed)
641
+ field_authed = sync(field_authed)
642
+ end
643
+ @field_authorization_results[idx] = field_authed
644
+ rescue GraphQL::UnauthorizedFieldError => field_auth_err
645
+ field_auth_err.field ||= @field_definition
646
+ (@field_authorization_errors ||= {})[idx] = field_auth_err
647
+ end
648
+
649
+ # Runs once for each time this step was enqueued for field authorization.
650
+ # The index is taken before +authorized?+ runs, so it's still correct if this Fiber pauses.
651
+ # When the last object is done, the step is enqueued again to call +finish_field_authorizations+.
652
+ def authorize_next_field_object
653
+ idx = @field_authorization_next_idx
654
+ @field_authorization_next_idx += 1
655
+ begin
656
+ authorize_field_at(idx, @selections_step.query.context)
657
+ rescue StandardError => err
658
+ (@field_authorization_errors ||= {})[idx] = err
659
+ end
660
+ @field_authorization_pending -= 1
661
+ if @field_authorization_pending == 0
662
+ @runner.add_step(self)
663
+ end
664
+ end
665
+
666
+ def finish_field_authorizations
667
+ if (errors = @field_authorization_errors)
668
+ @field_authorization_objects.size.times do |idx|
669
+ err = errors[idx]
670
+ if err && !err.is_a?(GraphQL::UnauthorizedFieldError)
671
+ raise err
672
+ end
673
+ end
674
+ end
675
+ authorized_objects = collect_field_authorizations
676
+ if authorized_objects
677
+ execute_authorized_field(authorized_objects)
678
+ end
679
+ rescue StandardError => err
680
+ handle_execute_field_error(err)
681
+ end
682
+
683
+ def clear_field_authorizations
684
+ @field_authorization_objects = @field_authorization_results = @field_authorization_errors = nil
685
+ @field_authorization_next_idx = @field_authorization_pending = nil
686
+ end
687
+
688
+ # Applies +unauthorized_field+ for denied objects, in object order.
689
+ # Returns the objects to resolve, or +nil+ if none are left.
690
+ def collect_field_authorizations
691
+ objects = @field_authorization_objects
692
+ auth_results = @field_authorization_results
693
+ errors = @field_authorization_errors
694
+ clear_field_authorizations
695
+ ctx = @selections_step.query.context
696
+ authorized_objects = []
697
+ authorized_results = []
698
+ objects.each_with_index do |o, i|
699
+ err = errors && errors[i]
700
+ if !err && auth_results[i]
701
+ authorized_results << @results[i]
702
+ authorized_objects << o
703
+ else
704
+ begin
705
+ err ||= GraphQL::UnauthorizedFieldError.new(object: o, type: @parent_type, context: ctx, field: @field_definition)
706
+ new_obj = ctx.schema.unauthorized_field(err)
707
+ if !new_obj.nil?
708
+ authorized_objects << new_obj
709
+ authorized_results << @results[i]
710
+ end
711
+ rescue GraphQL::ExecutionError => exec_err
712
+ add_graphql_error(@results[i], key, exec_err)
713
+ end
714
+ end
715
+ end
716
+
717
+ if authorized_objects.size == 0
718
+ return nil
719
+ end
720
+ @results = authorized_results
721
+ authorized_objects
722
+ end
723
+
627
724
  def build_graphql_result(graphql_result, key, field_result, return_type, is_nn, is_list, is_from_array) # rubocop:disable Metrics/ParameterLists
628
725
  if field_result.nil?
629
726
  if is_nn
@@ -701,25 +798,25 @@ module GraphQL
701
798
  when :resolve_batch
702
799
  begin
703
800
  method_receiver.public_send(@field_definition.execution_mode_key, objects, context, **args_hash)
704
- rescue GraphQL::ExecutionError => exec_err
705
- error_instance_array(objects.size, exec_err)
706
- rescue StandardError => stderr
801
+ rescue GraphQL::ExecutionError => batch_err
802
+ error_instance_array(objects.size, batch_err)
803
+ rescue StandardError => batch_stderr
707
804
  begin
708
- context.query.handle_or_reraise(stderr, field: @field_definition, arguments: @arguments, object: nil)
709
- rescue GraphQL::ExecutionError => exec_err
710
- error_instance_array(objects.size, exec_err)
805
+ context.query.handle_or_reraise(batch_stderr, field: @field_definition, arguments: @arguments, object: nil)
806
+ rescue GraphQL::ExecutionError => batch_err
807
+ error_instance_array(objects.size, batch_err)
711
808
  end
712
809
  end
713
810
  when :resolve_static
714
811
  result = begin
715
812
  method_receiver.public_send(@field_definition.execution_mode_key, context, **args_hash)
716
- rescue GraphQL::ExecutionError => err
717
- err
718
- rescue StandardError => stderr
813
+ rescue GraphQL::ExecutionError => static_err
814
+ static_err
815
+ rescue StandardError => static_stderr
719
816
  begin
720
- context.query.handle_or_reraise(stderr, field: @field_definition, arguments: @arguments, object: nil)
721
- rescue GraphQL::ExecutionError => err
722
- err
817
+ context.query.handle_or_reraise(static_stderr, field: @field_definition, arguments: @arguments, object: nil)
818
+ rescue GraphQL::ExecutionError => static_err
819
+ static_err
723
820
  end
724
821
  end
725
822
  Array.new(objects.size, result)
@@ -797,8 +894,13 @@ module GraphQL
797
894
  end
798
895
  results
799
896
  when :resolve_legacy_instance_method
800
- @selections_step.graphql_objects.map do |obj_inst|
801
- obj_inst.public_send(@field_definition.execution_mode_key, **args_hash)
897
+ graphql_objects = if objects.equal?(@selections_step.objects)
898
+ @selections_step.graphql_objects
899
+ else
900
+ objects.map { |object| @parent_type.scoped_new(object, context) }
901
+ end
902
+ graphql_objects.map do |graphql_object|
903
+ graphql_object.public_send(@field_definition.execution_mode_key, **args_hash)
802
904
  rescue GraphQL::ExecutionError => exec_err
803
905
  exec_err
804
906
  end
@@ -1,4 +1,5 @@
1
1
  # frozen_string_literal: true
2
+ # typed: true
2
3
  module GraphQL
3
4
  module Execution
4
5
  class Finalize
@@ -39,11 +40,16 @@ module GraphQL
39
40
  tf[key] = err
40
41
  @finalizers_count += 1
41
42
  elsif value_at_key.is_a?(Array)
42
- value_at_key.each_with_index do |el, idx|
43
- if el.equal?(err)
44
- tf = @finalizers[value_at_key] ||= {}.compare_by_identity
45
- tf[idx] = err
46
- @finalizers_count += 1
43
+ pending_arrays = [value_at_key]
44
+ while (array = pending_arrays.pop)
45
+ array.each_with_index do |el, idx|
46
+ if el.equal?(err)
47
+ array_tf = @finalizers[array] ||= {}.compare_by_identity
48
+ array_tf[idx] = err
49
+ @finalizers_count += 1
50
+ elsif el.is_a?(Array)
51
+ pending_arrays << el
52
+ end
47
53
  end
48
54
  end
49
55
  end
@@ -175,7 +181,7 @@ module GraphQL
175
181
  inner_type = inner_type.of_type
176
182
  end
177
183
 
178
- new_invalid_null = false
184
+ new_invalid_null = false #: bool
179
185
 
180
186
  if (f = finalizers(result_arr, nil))
181
187
  run_finalizers(@current_result_path.dup, f, result_arr, nil)