graphql 0.16.0 → 2.0.15

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 (490) hide show
  1. checksums.yaml +5 -5
  2. data/.yardopts +5 -0
  3. data/lib/generators/graphql/core.rb +69 -0
  4. data/lib/generators/graphql/enum_generator.rb +27 -0
  5. data/lib/generators/graphql/field_extractor.rb +31 -0
  6. data/lib/generators/graphql/input_generator.rb +50 -0
  7. data/lib/generators/graphql/install/mutation_root_generator.rb +34 -0
  8. data/lib/generators/graphql/install/templates/base_mutation.erb +10 -0
  9. data/lib/generators/graphql/install/templates/mutation_type.erb +12 -0
  10. data/lib/generators/graphql/install_generator.rb +197 -0
  11. data/lib/generators/graphql/interface_generator.rb +27 -0
  12. data/lib/generators/graphql/loader_generator.rb +21 -0
  13. data/lib/generators/graphql/mutation_create_generator.rb +22 -0
  14. data/lib/generators/graphql/mutation_delete_generator.rb +22 -0
  15. data/lib/generators/graphql/mutation_generator.rb +30 -0
  16. data/lib/generators/graphql/mutation_update_generator.rb +22 -0
  17. data/lib/generators/graphql/object_generator.rb +50 -0
  18. data/lib/generators/graphql/orm_mutations_base.rb +40 -0
  19. data/lib/generators/graphql/relay.rb +49 -0
  20. data/lib/generators/graphql/relay_generator.rb +21 -0
  21. data/lib/generators/graphql/scalar_generator.rb +22 -0
  22. data/lib/generators/graphql/templates/base_argument.erb +6 -0
  23. data/lib/generators/graphql/templates/base_connection.erb +8 -0
  24. data/lib/generators/graphql/templates/base_edge.erb +8 -0
  25. data/lib/generators/graphql/templates/base_enum.erb +6 -0
  26. data/lib/generators/graphql/templates/base_field.erb +7 -0
  27. data/lib/generators/graphql/templates/base_input_object.erb +7 -0
  28. data/lib/generators/graphql/templates/base_interface.erb +9 -0
  29. data/lib/generators/graphql/templates/base_object.erb +7 -0
  30. data/lib/generators/graphql/templates/base_scalar.erb +6 -0
  31. data/lib/generators/graphql/templates/base_union.erb +6 -0
  32. data/lib/generators/graphql/templates/enum.erb +11 -0
  33. data/lib/generators/graphql/templates/graphql_controller.erb +52 -0
  34. data/lib/generators/graphql/templates/input.erb +9 -0
  35. data/lib/generators/graphql/templates/interface.erb +10 -0
  36. data/lib/generators/graphql/templates/loader.erb +19 -0
  37. data/lib/generators/graphql/templates/mutation.erb +16 -0
  38. data/lib/generators/graphql/templates/mutation_create.erb +20 -0
  39. data/lib/generators/graphql/templates/mutation_delete.erb +20 -0
  40. data/lib/generators/graphql/templates/mutation_update.erb +21 -0
  41. data/lib/generators/graphql/templates/node_type.erb +9 -0
  42. data/lib/generators/graphql/templates/object.erb +10 -0
  43. data/lib/generators/graphql/templates/query_type.erb +15 -0
  44. data/lib/generators/graphql/templates/scalar.erb +17 -0
  45. data/lib/generators/graphql/templates/schema.erb +30 -0
  46. data/lib/generators/graphql/templates/union.erb +9 -0
  47. data/lib/generators/graphql/type_generator.rb +135 -0
  48. data/lib/generators/graphql/union_generator.rb +33 -0
  49. data/lib/graphql/analysis/ast/analyzer.rb +84 -0
  50. data/lib/graphql/analysis/ast/field_usage.rb +57 -0
  51. data/lib/graphql/analysis/ast/max_query_complexity.rb +22 -0
  52. data/lib/graphql/analysis/ast/max_query_depth.rb +22 -0
  53. data/lib/graphql/analysis/ast/query_complexity.rb +230 -0
  54. data/lib/graphql/analysis/ast/query_depth.rb +55 -0
  55. data/lib/graphql/analysis/ast/visitor.rb +269 -0
  56. data/lib/graphql/analysis/ast.rb +81 -0
  57. data/lib/graphql/analysis.rb +2 -5
  58. data/lib/graphql/analysis_error.rb +1 -0
  59. data/lib/graphql/backtrace/inspect_result.rb +50 -0
  60. data/lib/graphql/backtrace/table.rb +141 -0
  61. data/lib/graphql/backtrace/traced_error.rb +54 -0
  62. data/lib/graphql/backtrace/tracer.rb +80 -0
  63. data/lib/graphql/backtrace.rb +58 -0
  64. data/lib/graphql/coercion_error.rb +13 -0
  65. data/lib/graphql/dataloader/null_dataloader.rb +24 -0
  66. data/lib/graphql/dataloader/request.rb +19 -0
  67. data/lib/graphql/dataloader/request_all.rb +19 -0
  68. data/lib/graphql/dataloader/source.rb +164 -0
  69. data/lib/graphql/dataloader.rb +311 -0
  70. data/lib/graphql/date_encoding_error.rb +16 -0
  71. data/lib/graphql/deprecation.rb +9 -0
  72. data/lib/graphql/dig.rb +19 -0
  73. data/lib/graphql/execution/directive_checks.rb +37 -0
  74. data/lib/graphql/execution/errors.rb +93 -0
  75. data/lib/graphql/execution/interpreter/argument_value.rb +28 -0
  76. data/lib/graphql/execution/interpreter/arguments.rb +88 -0
  77. data/lib/graphql/execution/interpreter/arguments_cache.rb +105 -0
  78. data/lib/graphql/execution/interpreter/execution_errors.rb +29 -0
  79. data/lib/graphql/execution/interpreter/handles_raw_value.rb +18 -0
  80. data/lib/graphql/execution/interpreter/resolve.rb +77 -0
  81. data/lib/graphql/execution/interpreter/runtime.rb +994 -0
  82. data/lib/graphql/execution/interpreter.rb +226 -0
  83. data/lib/graphql/execution/lazy/lazy_method_map.rb +98 -0
  84. data/lib/graphql/execution/lazy.rb +75 -0
  85. data/lib/graphql/execution/lookahead.rb +311 -0
  86. data/lib/graphql/execution/multiplex.rb +45 -0
  87. data/lib/graphql/execution.rb +18 -0
  88. data/lib/graphql/execution_error.rb +34 -1
  89. data/lib/graphql/filter.rb +53 -0
  90. data/lib/graphql/integer_decoding_error.rb +17 -0
  91. data/lib/graphql/integer_encoding_error.rb +36 -0
  92. data/lib/graphql/introspection/base_object.rb +13 -0
  93. data/lib/graphql/introspection/directive_location_enum.rb +12 -5
  94. data/lib/graphql/introspection/directive_type.rb +30 -10
  95. data/lib/graphql/introspection/dynamic_fields.rb +12 -0
  96. data/lib/graphql/introspection/entry_points.rb +22 -0
  97. data/lib/graphql/introspection/enum_value_type.rb +21 -8
  98. data/lib/graphql/introspection/field_type.rb +26 -10
  99. data/lib/graphql/introspection/input_value_type.rb +64 -14
  100. data/lib/graphql/introspection/introspection_query.rb +7 -76
  101. data/lib/graphql/introspection/schema_type.rb +42 -17
  102. data/lib/graphql/introspection/type_kind_enum.rb +11 -5
  103. data/lib/graphql/introspection/type_type.rb +104 -16
  104. data/lib/graphql/introspection.rb +104 -13
  105. data/lib/graphql/invalid_name_error.rb +11 -0
  106. data/lib/graphql/invalid_null_error.rb +36 -8
  107. data/lib/graphql/language/block_string.rb +99 -0
  108. data/lib/graphql/language/cache.rb +37 -0
  109. data/lib/graphql/language/definition_slice.rb +41 -0
  110. data/lib/graphql/language/document_from_schema_definition.rb +335 -0
  111. data/lib/graphql/language/generation.rb +16 -86
  112. data/lib/graphql/language/lexer.rb +1436 -705
  113. data/lib/graphql/language/lexer.rl +172 -64
  114. data/lib/graphql/language/nodes.rb +617 -105
  115. data/lib/graphql/language/parser.rb +1524 -430
  116. data/lib/graphql/language/parser.y +348 -73
  117. data/lib/graphql/language/printer.rb +386 -0
  118. data/lib/graphql/language/sanitized_printer.rb +222 -0
  119. data/lib/graphql/language/token.rb +16 -3
  120. data/lib/graphql/language/visitor.rb +169 -25
  121. data/lib/graphql/language.rb +30 -0
  122. data/lib/graphql/load_application_object_failed_error.rb +22 -0
  123. data/lib/graphql/name_validator.rb +11 -0
  124. data/lib/graphql/pagination/active_record_relation_connection.rb +85 -0
  125. data/lib/graphql/pagination/array_connection.rb +79 -0
  126. data/lib/graphql/pagination/connection.rb +253 -0
  127. data/lib/graphql/pagination/connections.rb +135 -0
  128. data/lib/graphql/pagination/mongoid_relation_connection.rb +25 -0
  129. data/lib/graphql/pagination/relation_connection.rb +228 -0
  130. data/lib/graphql/pagination/sequel_dataset_connection.rb +28 -0
  131. data/lib/graphql/pagination.rb +6 -0
  132. data/lib/graphql/parse_error.rb +24 -0
  133. data/lib/graphql/query/context.rb +266 -12
  134. data/lib/graphql/query/fingerprint.rb +26 -0
  135. data/lib/graphql/query/input_validation_result.rb +34 -7
  136. data/lib/graphql/query/null_context.rb +52 -0
  137. data/lib/graphql/query/result.rb +63 -0
  138. data/lib/graphql/query/validation_pipeline.rb +114 -0
  139. data/lib/graphql/query/variable_validation_error.rb +27 -3
  140. data/lib/graphql/query/variables.rb +75 -24
  141. data/lib/graphql/query.rb +359 -92
  142. data/lib/graphql/railtie.rb +13 -0
  143. data/lib/graphql/rake_task/validate.rb +63 -0
  144. data/lib/graphql/rake_task.rb +146 -0
  145. data/lib/graphql/relay/range_add.rb +52 -0
  146. data/lib/graphql/relay.rb +3 -0
  147. data/lib/graphql/rubocop/graphql/base_cop.rb +36 -0
  148. data/lib/graphql/rubocop/graphql/default_null_true.rb +43 -0
  149. data/lib/graphql/rubocop/graphql/default_required_true.rb +43 -0
  150. data/lib/graphql/rubocop.rb +4 -0
  151. data/lib/graphql/runtime_type_error.rb +5 -0
  152. data/lib/graphql/schema/addition.rb +245 -0
  153. data/lib/graphql/schema/argument.rb +395 -0
  154. data/lib/graphql/schema/base_64_bp.rb +26 -0
  155. data/lib/graphql/schema/base_64_encoder.rb +21 -0
  156. data/lib/graphql/schema/build_from_definition/resolve_map/default_resolve.rb +47 -0
  157. data/lib/graphql/schema/build_from_definition/resolve_map.rb +78 -0
  158. data/lib/graphql/schema/build_from_definition.rb +492 -0
  159. data/lib/graphql/schema/built_in_types.rb +12 -0
  160. data/lib/graphql/schema/directive/deprecated.rb +18 -0
  161. data/lib/graphql/schema/directive/feature.rb +66 -0
  162. data/lib/graphql/schema/directive/flagged.rb +57 -0
  163. data/lib/graphql/schema/directive/include.rb +25 -0
  164. data/lib/graphql/schema/directive/one_of.rb +12 -0
  165. data/lib/graphql/schema/directive/skip.rb +25 -0
  166. data/lib/graphql/schema/directive/transform.rb +60 -0
  167. data/lib/graphql/schema/directive.rb +212 -0
  168. data/lib/graphql/schema/enum.rb +176 -0
  169. data/lib/graphql/schema/enum_value.rb +77 -0
  170. data/lib/graphql/schema/field/connection_extension.rb +80 -0
  171. data/lib/graphql/schema/field/scope_extension.rb +22 -0
  172. data/lib/graphql/schema/field.rb +862 -0
  173. data/lib/graphql/schema/field_extension.rb +156 -0
  174. data/lib/graphql/schema/find_inherited_value.rb +36 -0
  175. data/lib/graphql/schema/finder.rb +155 -0
  176. data/lib/graphql/schema/input_object.rb +258 -0
  177. data/lib/graphql/schema/interface.rb +113 -0
  178. data/lib/graphql/schema/introspection_system.rb +164 -0
  179. data/lib/graphql/schema/invalid_type_error.rb +1 -0
  180. data/lib/graphql/schema/late_bound_type.rb +37 -0
  181. data/lib/graphql/schema/list.rb +86 -0
  182. data/lib/graphql/schema/loader.rb +228 -0
  183. data/lib/graphql/schema/member/base_dsl_methods.rb +124 -0
  184. data/lib/graphql/schema/member/build_type.rb +178 -0
  185. data/lib/graphql/schema/member/graphql_type_names.rb +21 -0
  186. data/lib/graphql/schema/member/has_arguments.rb +376 -0
  187. data/lib/graphql/schema/member/has_ast_node.rb +20 -0
  188. data/lib/graphql/schema/member/has_deprecation_reason.rb +25 -0
  189. data/lib/graphql/schema/member/has_directives.rb +113 -0
  190. data/lib/graphql/schema/member/has_fields.rb +163 -0
  191. data/lib/graphql/schema/member/has_interfaces.rb +88 -0
  192. data/lib/graphql/schema/member/has_path.rb +25 -0
  193. data/lib/graphql/schema/member/has_unresolved_type_error.rb +15 -0
  194. data/lib/graphql/schema/member/has_validators.rb +31 -0
  195. data/lib/graphql/schema/member/relay_shortcuts.rb +73 -0
  196. data/lib/graphql/schema/member/scoped.rb +21 -0
  197. data/lib/graphql/schema/member/type_system_helpers.rb +38 -0
  198. data/lib/graphql/schema/member/validates_input.rb +33 -0
  199. data/lib/graphql/schema/member.rb +39 -0
  200. data/lib/graphql/schema/mutation.rb +85 -0
  201. data/lib/graphql/schema/non_null.rb +67 -0
  202. data/lib/graphql/schema/null_mask.rb +11 -0
  203. data/lib/graphql/schema/object.rb +117 -0
  204. data/lib/graphql/schema/printer.rb +72 -128
  205. data/lib/graphql/schema/relay_classic_mutation.rb +179 -0
  206. data/lib/graphql/schema/resolver/has_payload_type.rb +106 -0
  207. data/lib/graphql/schema/resolver.rb +402 -0
  208. data/lib/graphql/schema/scalar.rb +68 -0
  209. data/lib/graphql/schema/subscription.rb +148 -0
  210. data/lib/graphql/schema/timeout.rb +123 -0
  211. data/lib/graphql/schema/type_expression.rb +29 -5
  212. data/lib/graphql/schema/type_membership.rb +51 -0
  213. data/lib/graphql/schema/union.rb +81 -0
  214. data/lib/graphql/schema/unique_within_type.rb +34 -0
  215. data/lib/graphql/schema/validator/allow_blank_validator.rb +29 -0
  216. data/lib/graphql/schema/validator/allow_null_validator.rb +26 -0
  217. data/lib/graphql/schema/validator/exclusion_validator.rb +33 -0
  218. data/lib/graphql/schema/validator/format_validator.rb +48 -0
  219. data/lib/graphql/schema/validator/inclusion_validator.rb +35 -0
  220. data/lib/graphql/schema/validator/length_validator.rb +59 -0
  221. data/lib/graphql/schema/validator/numericality_validator.rb +82 -0
  222. data/lib/graphql/schema/validator/required_validator.rb +82 -0
  223. data/lib/graphql/schema/validator.rb +171 -0
  224. data/lib/graphql/schema/warden.rb +413 -0
  225. data/lib/graphql/schema/wrapper.rb +24 -0
  226. data/lib/graphql/schema.rb +1179 -104
  227. data/lib/graphql/static_validation/all_rules.rb +14 -0
  228. data/lib/graphql/static_validation/base_visitor.rb +200 -0
  229. data/lib/graphql/static_validation/definition_dependencies.rb +198 -0
  230. data/lib/graphql/static_validation/error.rb +46 -0
  231. data/lib/graphql/static_validation/interpreter_visitor.rb +14 -0
  232. data/lib/graphql/static_validation/literal_validator.rb +113 -22
  233. data/lib/graphql/static_validation/rules/argument_literals_are_compatible.rb +59 -11
  234. data/lib/graphql/static_validation/rules/argument_literals_are_compatible_error.rb +48 -0
  235. data/lib/graphql/static_validation/rules/argument_names_are_unique.rb +31 -0
  236. data/lib/graphql/static_validation/rules/argument_names_are_unique_error.rb +30 -0
  237. data/lib/graphql/static_validation/rules/arguments_are_defined.rb +62 -8
  238. data/lib/graphql/static_validation/rules/arguments_are_defined_error.rb +37 -0
  239. data/lib/graphql/static_validation/rules/directives_are_defined.rb +20 -13
  240. data/lib/graphql/static_validation/rules/directives_are_defined_error.rb +29 -0
  241. data/lib/graphql/static_validation/rules/directives_are_in_valid_locations.rb +32 -26
  242. data/lib/graphql/static_validation/rules/directives_are_in_valid_locations_error.rb +31 -0
  243. data/lib/graphql/static_validation/rules/fields_are_defined_on_type.rb +21 -23
  244. data/lib/graphql/static_validation/rules/fields_are_defined_on_type_error.rb +32 -0
  245. data/lib/graphql/static_validation/rules/fields_have_appropriate_selections.rb +55 -18
  246. data/lib/graphql/static_validation/rules/fields_have_appropriate_selections_error.rb +31 -0
  247. data/lib/graphql/static_validation/rules/fields_will_merge.rb +390 -70
  248. data/lib/graphql/static_validation/rules/fields_will_merge_error.rb +53 -0
  249. data/lib/graphql/static_validation/rules/fragment_names_are_unique.rb +30 -0
  250. data/lib/graphql/static_validation/rules/fragment_names_are_unique_error.rb +29 -0
  251. data/lib/graphql/static_validation/rules/fragment_spreads_are_possible.rb +54 -37
  252. data/lib/graphql/static_validation/rules/fragment_spreads_are_possible_error.rb +35 -0
  253. data/lib/graphql/static_validation/rules/fragment_types_exist.rb +26 -16
  254. data/lib/graphql/static_validation/rules/fragment_types_exist_error.rb +29 -0
  255. data/lib/graphql/static_validation/rules/fragments_are_finite.rb +13 -19
  256. data/lib/graphql/static_validation/rules/fragments_are_finite_error.rb +29 -0
  257. data/lib/graphql/static_validation/rules/fragments_are_named.rb +16 -0
  258. data/lib/graphql/static_validation/rules/fragments_are_named_error.rb +26 -0
  259. data/lib/graphql/static_validation/rules/fragments_are_on_composite_types.rb +25 -20
  260. data/lib/graphql/static_validation/rules/fragments_are_on_composite_types_error.rb +30 -0
  261. data/lib/graphql/static_validation/rules/fragments_are_used.rb +22 -33
  262. data/lib/graphql/static_validation/rules/fragments_are_used_error.rb +29 -0
  263. data/lib/graphql/static_validation/rules/input_object_names_are_unique.rb +30 -0
  264. data/lib/graphql/static_validation/rules/input_object_names_are_unique_error.rb +30 -0
  265. data/lib/graphql/static_validation/rules/mutation_root_exists.rb +17 -0
  266. data/lib/graphql/static_validation/rules/mutation_root_exists_error.rb +26 -0
  267. data/lib/graphql/static_validation/rules/no_definitions_are_present.rb +41 -0
  268. data/lib/graphql/static_validation/rules/no_definitions_are_present_error.rb +25 -0
  269. data/lib/graphql/static_validation/rules/one_of_input_objects_are_valid.rb +66 -0
  270. data/lib/graphql/static_validation/rules/one_of_input_objects_are_valid_error.rb +29 -0
  271. data/lib/graphql/static_validation/rules/operation_names_are_valid.rb +36 -0
  272. data/lib/graphql/static_validation/rules/operation_names_are_valid_error.rb +28 -0
  273. data/lib/graphql/static_validation/rules/query_root_exists.rb +17 -0
  274. data/lib/graphql/static_validation/rules/query_root_exists_error.rb +26 -0
  275. data/lib/graphql/static_validation/rules/required_arguments_are_present.rb +22 -21
  276. data/lib/graphql/static_validation/rules/required_arguments_are_present_error.rb +35 -0
  277. data/lib/graphql/static_validation/rules/required_input_object_attributes_are_present.rb +59 -0
  278. data/lib/graphql/static_validation/rules/required_input_object_attributes_are_present_error.rb +35 -0
  279. data/lib/graphql/static_validation/rules/subscription_root_exists.rb +17 -0
  280. data/lib/graphql/static_validation/rules/subscription_root_exists_error.rb +26 -0
  281. data/lib/graphql/static_validation/rules/unique_directives_per_location.rb +56 -0
  282. data/lib/graphql/static_validation/rules/unique_directives_per_location_error.rb +29 -0
  283. data/lib/graphql/static_validation/rules/variable_default_values_are_correctly_typed.rb +36 -18
  284. data/lib/graphql/static_validation/rules/variable_default_values_are_correctly_typed_error.rb +39 -0
  285. data/lib/graphql/static_validation/rules/variable_names_are_unique.rb +24 -0
  286. data/lib/graphql/static_validation/rules/variable_names_are_unique_error.rb +29 -0
  287. data/lib/graphql/static_validation/rules/variable_usages_are_allowed.rb +103 -39
  288. data/lib/graphql/static_validation/rules/variable_usages_are_allowed_error.rb +38 -0
  289. data/lib/graphql/static_validation/rules/variables_are_input_types.rb +22 -14
  290. data/lib/graphql/static_validation/rules/variables_are_input_types_error.rb +32 -0
  291. data/lib/graphql/static_validation/rules/variables_are_used_and_defined.rb +92 -70
  292. data/lib/graphql/static_validation/rules/variables_are_used_and_defined_error.rb +37 -0
  293. data/lib/graphql/static_validation/type_stack.rb +85 -24
  294. data/lib/graphql/static_validation/validation_context.rb +25 -46
  295. data/lib/graphql/static_validation/validation_timeout_error.rb +25 -0
  296. data/lib/graphql/static_validation/validator.rb +46 -15
  297. data/lib/graphql/static_validation.rb +6 -3
  298. data/lib/graphql/string_encoding_error.rb +20 -0
  299. data/lib/graphql/subscriptions/action_cable_subscriptions.rb +247 -0
  300. data/lib/graphql/subscriptions/broadcast_analyzer.rb +81 -0
  301. data/lib/graphql/subscriptions/default_subscription_resolve_extension.rb +58 -0
  302. data/lib/graphql/subscriptions/event.rb +144 -0
  303. data/lib/graphql/subscriptions/instrumentation.rb +28 -0
  304. data/lib/graphql/subscriptions/serialize.rb +158 -0
  305. data/lib/graphql/subscriptions.rb +306 -0
  306. data/lib/graphql/tracing/active_support_notifications_tracing.rb +21 -0
  307. data/lib/graphql/tracing/appoptics_tracing.rb +173 -0
  308. data/lib/graphql/tracing/appsignal_tracing.rb +51 -0
  309. data/lib/graphql/tracing/data_dog_tracing.rb +100 -0
  310. data/lib/graphql/tracing/instrumentation_tracing.rb +83 -0
  311. data/lib/graphql/tracing/new_relic_tracing.rb +51 -0
  312. data/lib/graphql/tracing/notifications_tracing.rb +59 -0
  313. data/lib/graphql/tracing/platform_tracing.rb +122 -0
  314. data/lib/graphql/tracing/prometheus_tracing/graphql_collector.rb +32 -0
  315. data/lib/graphql/tracing/prometheus_tracing.rb +67 -0
  316. data/lib/graphql/tracing/scout_tracing.rb +54 -0
  317. data/lib/graphql/tracing/statsd_tracing.rb +42 -0
  318. data/lib/graphql/tracing.rb +94 -0
  319. data/lib/graphql/type_kinds.rb +50 -22
  320. data/lib/graphql/types/big_int.rb +23 -0
  321. data/lib/graphql/types/boolean.rb +18 -0
  322. data/lib/graphql/types/float.rb +19 -0
  323. data/lib/graphql/types/id.rb +24 -0
  324. data/lib/graphql/types/int.rb +36 -0
  325. data/lib/graphql/types/iso_8601_date.rb +45 -0
  326. data/lib/graphql/types/iso_8601_date_time.rb +76 -0
  327. data/lib/graphql/types/json.rb +25 -0
  328. data/lib/graphql/types/relay/base_connection.rb +49 -0
  329. data/lib/graphql/types/relay/base_edge.rb +29 -0
  330. data/lib/graphql/types/relay/connection_behaviors.rb +154 -0
  331. data/lib/graphql/types/relay/default_relay.rb +21 -0
  332. data/lib/graphql/types/relay/edge_behaviors.rb +64 -0
  333. data/lib/graphql/types/relay/has_node_field.rb +41 -0
  334. data/lib/graphql/types/relay/has_nodes_field.rb +41 -0
  335. data/lib/graphql/types/relay/node.rb +15 -0
  336. data/lib/graphql/types/relay/node_behaviors.rb +19 -0
  337. data/lib/graphql/types/relay/page_info.rb +11 -0
  338. data/lib/graphql/types/relay/page_info_behaviors.rb +25 -0
  339. data/lib/graphql/types/relay.rb +39 -0
  340. data/lib/graphql/types/string.rb +29 -0
  341. data/lib/graphql/types.rb +11 -0
  342. data/lib/graphql/unauthorized_error.rb +29 -0
  343. data/lib/graphql/unauthorized_field_error.rb +23 -0
  344. data/lib/graphql/unresolved_type_error.rb +35 -0
  345. data/lib/graphql/version.rb +2 -1
  346. data/lib/graphql.rb +86 -41
  347. data/readme.md +15 -101
  348. metadata +394 -279
  349. data/lib/graphql/analysis/analyze_query.rb +0 -73
  350. data/lib/graphql/analysis/max_query_complexity.rb +0 -25
  351. data/lib/graphql/analysis/max_query_depth.rb +0 -25
  352. data/lib/graphql/analysis/query_complexity.rb +0 -122
  353. data/lib/graphql/analysis/query_depth.rb +0 -54
  354. data/lib/graphql/argument.rb +0 -25
  355. data/lib/graphql/base_type.rb +0 -115
  356. data/lib/graphql/boolean_type.rb +0 -9
  357. data/lib/graphql/define/assign_argument.rb +0 -20
  358. data/lib/graphql/define/assign_enum_value.rb +0 -16
  359. data/lib/graphql/define/assign_object_field.rb +0 -21
  360. data/lib/graphql/define/assignment_dictionary.rb +0 -26
  361. data/lib/graphql/define/defined_object_proxy.rb +0 -32
  362. data/lib/graphql/define/instance_definable.rb +0 -79
  363. data/lib/graphql/define/non_null_with_bang.rb +0 -15
  364. data/lib/graphql/define/type_definer.rb +0 -30
  365. data/lib/graphql/define.rb +0 -8
  366. data/lib/graphql/directive/include_directive.rb +0 -10
  367. data/lib/graphql/directive/skip_directive.rb +0 -11
  368. data/lib/graphql/directive.rb +0 -49
  369. data/lib/graphql/enum_type.rb +0 -95
  370. data/lib/graphql/field.rb +0 -131
  371. data/lib/graphql/float_type.rb +0 -5
  372. data/lib/graphql/id_type.rb +0 -12
  373. data/lib/graphql/input_object_type.rb +0 -71
  374. data/lib/graphql/int_type.rb +0 -5
  375. data/lib/graphql/interface_type.rb +0 -38
  376. data/lib/graphql/internal_representation/node.rb +0 -81
  377. data/lib/graphql/internal_representation/rewrite.rb +0 -177
  378. data/lib/graphql/internal_representation.rb +0 -2
  379. data/lib/graphql/introspection/arguments_field.rb +0 -5
  380. data/lib/graphql/introspection/enum_values_field.rb +0 -13
  381. data/lib/graphql/introspection/fields_field.rb +0 -13
  382. data/lib/graphql/introspection/input_fields_field.rb +0 -12
  383. data/lib/graphql/introspection/interfaces_field.rb +0 -5
  384. data/lib/graphql/introspection/of_type_field.rb +0 -6
  385. data/lib/graphql/introspection/possible_types_field.rb +0 -11
  386. data/lib/graphql/introspection/schema_field.rb +0 -15
  387. data/lib/graphql/introspection/type_by_name_field.rb +0 -16
  388. data/lib/graphql/introspection/typename_field.rb +0 -15
  389. data/lib/graphql/list_type.rb +0 -46
  390. data/lib/graphql/non_null_type.rb +0 -43
  391. data/lib/graphql/object_type.rb +0 -93
  392. data/lib/graphql/query/arguments.rb +0 -76
  393. data/lib/graphql/query/directive_resolution.rb +0 -16
  394. data/lib/graphql/query/executor.rb +0 -45
  395. data/lib/graphql/query/literal_input.rb +0 -90
  396. data/lib/graphql/query/serial_execution/execution_context.rb +0 -31
  397. data/lib/graphql/query/serial_execution/field_resolution.rb +0 -82
  398. data/lib/graphql/query/serial_execution/operation_resolution.rb +0 -27
  399. data/lib/graphql/query/serial_execution/selection_resolution.rb +0 -42
  400. data/lib/graphql/query/serial_execution/value_resolution.rb +0 -107
  401. data/lib/graphql/query/serial_execution.rb +0 -41
  402. data/lib/graphql/query/type_resolver.rb +0 -25
  403. data/lib/graphql/scalar_type.rb +0 -53
  404. data/lib/graphql/schema/catchall_middleware.rb +0 -34
  405. data/lib/graphql/schema/middleware_chain.rb +0 -28
  406. data/lib/graphql/schema/possible_types.rb +0 -34
  407. data/lib/graphql/schema/reduce_types.rb +0 -68
  408. data/lib/graphql/schema/rescue_middleware.rb +0 -53
  409. data/lib/graphql/schema/timeout_middleware.rb +0 -67
  410. data/lib/graphql/schema/type_map.rb +0 -30
  411. data/lib/graphql/schema/validation.rb +0 -164
  412. data/lib/graphql/static_validation/arguments_validator.rb +0 -48
  413. data/lib/graphql/static_validation/message.rb +0 -36
  414. data/lib/graphql/string_type.rb +0 -5
  415. data/lib/graphql/union_type.rb +0 -38
  416. data/spec/graphql/analysis/analyze_query_spec.rb +0 -50
  417. data/spec/graphql/analysis/max_query_complexity_spec.rb +0 -62
  418. data/spec/graphql/analysis/max_query_depth_spec.rb +0 -100
  419. data/spec/graphql/analysis/query_complexity_spec.rb +0 -235
  420. data/spec/graphql/analysis/query_depth_spec.rb +0 -80
  421. data/spec/graphql/argument_spec.rb +0 -20
  422. data/spec/graphql/base_type_spec.rb +0 -24
  423. data/spec/graphql/boolean_type_spec.rb +0 -20
  424. data/spec/graphql/define/instance_definable_spec.rb +0 -55
  425. data/spec/graphql/directive_spec.rb +0 -77
  426. data/spec/graphql/enum_type_spec.rb +0 -31
  427. data/spec/graphql/execution_error_spec.rb +0 -61
  428. data/spec/graphql/field_spec.rb +0 -92
  429. data/spec/graphql/float_type_spec.rb +0 -15
  430. data/spec/graphql/id_type_spec.rb +0 -32
  431. data/spec/graphql/input_object_type_spec.rb +0 -162
  432. data/spec/graphql/int_type_spec.rb +0 -15
  433. data/spec/graphql/interface_type_spec.rb +0 -56
  434. data/spec/graphql/internal_representation/rewrite_spec.rb +0 -120
  435. data/spec/graphql/introspection/directive_type_spec.rb +0 -50
  436. data/spec/graphql/introspection/input_value_type_spec.rb +0 -42
  437. data/spec/graphql/introspection/introspection_query_spec.rb +0 -10
  438. data/spec/graphql/introspection/schema_type_spec.rb +0 -45
  439. data/spec/graphql/introspection/type_type_spec.rb +0 -122
  440. data/spec/graphql/language/generation_spec.rb +0 -42
  441. data/spec/graphql/language/parser_spec.rb +0 -442
  442. data/spec/graphql/language/visitor_spec.rb +0 -49
  443. data/spec/graphql/list_type_spec.rb +0 -32
  444. data/spec/graphql/non_null_type_spec.rb +0 -31
  445. data/spec/graphql/object_type_spec.rb +0 -42
  446. data/spec/graphql/query/arguments_spec.rb +0 -25
  447. data/spec/graphql/query/context_spec.rb +0 -83
  448. data/spec/graphql/query/executor_spec.rb +0 -273
  449. data/spec/graphql/query/serial_execution/execution_context_spec.rb +0 -53
  450. data/spec/graphql/query/serial_execution/value_resolution_spec.rb +0 -66
  451. data/spec/graphql/query/type_resolver_spec.rb +0 -8
  452. data/spec/graphql/query/variables_spec.rb +0 -28
  453. data/spec/graphql/query_spec.rb +0 -363
  454. data/spec/graphql/scalar_type_spec.rb +0 -61
  455. data/spec/graphql/schema/catchall_middleware_spec.rb +0 -32
  456. data/spec/graphql/schema/middleware_chain_spec.rb +0 -42
  457. data/spec/graphql/schema/printer_spec.rb +0 -190
  458. data/spec/graphql/schema/reduce_types_spec.rb +0 -102
  459. data/spec/graphql/schema/rescue_middleware_spec.rb +0 -33
  460. data/spec/graphql/schema/timeout_middleware_spec.rb +0 -180
  461. data/spec/graphql/schema/type_expression_spec.rb +0 -38
  462. data/spec/graphql/schema/validation_spec.rb +0 -219
  463. data/spec/graphql/schema_spec.rb +0 -23
  464. data/spec/graphql/static_validation/rules/argument_literals_are_compatible_spec.rb +0 -63
  465. data/spec/graphql/static_validation/rules/arguments_are_defined_spec.rb +0 -48
  466. data/spec/graphql/static_validation/rules/directives_are_defined_spec.rb +0 -34
  467. data/spec/graphql/static_validation/rules/directives_are_in_valid_locations_spec.rb +0 -39
  468. data/spec/graphql/static_validation/rules/fields_are_defined_on_type_spec.rb +0 -60
  469. data/spec/graphql/static_validation/rules/fields_have_appropriate_selections_spec.rb +0 -31
  470. data/spec/graphql/static_validation/rules/fields_will_merge_spec.rb +0 -48
  471. data/spec/graphql/static_validation/rules/fragment_spreads_are_possible_spec.rb +0 -47
  472. data/spec/graphql/static_validation/rules/fragment_types_exist_spec.rb +0 -39
  473. data/spec/graphql/static_validation/rules/fragments_are_finite_spec.rb +0 -44
  474. data/spec/graphql/static_validation/rules/fragments_are_on_composite_types_spec.rb +0 -49
  475. data/spec/graphql/static_validation/rules/fragments_are_used_spec.rb +0 -25
  476. data/spec/graphql/static_validation/rules/required_arguments_are_present_spec.rb +0 -42
  477. data/spec/graphql/static_validation/rules/variable_default_values_are_correctly_typed_spec.rb +0 -44
  478. data/spec/graphql/static_validation/rules/variable_usages_are_allowed_spec.rb +0 -63
  479. data/spec/graphql/static_validation/rules/variables_are_input_types_spec.rb +0 -37
  480. data/spec/graphql/static_validation/rules/variables_are_used_and_defined_spec.rb +0 -53
  481. data/spec/graphql/static_validation/type_stack_spec.rb +0 -37
  482. data/spec/graphql/static_validation/validator_spec.rb +0 -69
  483. data/spec/graphql/string_type_spec.rb +0 -15
  484. data/spec/graphql/union_type_spec.rb +0 -31
  485. data/spec/spec_helper.rb +0 -18
  486. data/spec/support/dairy_app.rb +0 -309
  487. data/spec/support/dairy_data.rb +0 -23
  488. data/spec/support/minimum_input_object.rb +0 -16
  489. data/spec/support/star_wars_data.rb +0 -71
  490. data/spec/support/star_wars_schema.rb +0 -76
@@ -0,0 +1,994 @@
1
+ # frozen_string_literal: true
2
+
3
+ module GraphQL
4
+ module Execution
5
+ class Interpreter
6
+ # I think it would be even better if we could somehow make
7
+ # `continue_field` not recursive. "Trampolining" it somehow.
8
+ #
9
+ # @api private
10
+ class Runtime
11
+
12
+ module GraphQLResult
13
+ def initialize(result_name, parent_result)
14
+ @graphql_parent = parent_result
15
+ if parent_result && parent_result.graphql_dead
16
+ @graphql_dead = true
17
+ end
18
+ @graphql_result_name = result_name
19
+ # Jump through some hoops to avoid creating this duplicate storage if at all possible.
20
+ @graphql_metadata = nil
21
+ end
22
+
23
+ attr_accessor :graphql_dead
24
+ attr_reader :graphql_parent, :graphql_result_name
25
+
26
+ # Although these are used by only one of the Result classes,
27
+ # it's handy to have the methods implemented on both (even though they just return `nil`)
28
+ # because it makes it easy to check if anything is assigned.
29
+ # @return [nil, Array<String>]
30
+ attr_accessor :graphql_non_null_field_names
31
+ # @return [nil, true]
32
+ attr_accessor :graphql_non_null_list_items
33
+
34
+ # @return [Hash] Plain-Ruby result data (`@graphql_metadata` contains Result wrapper objects)
35
+ attr_accessor :graphql_result_data
36
+ end
37
+
38
+ class GraphQLResultHash
39
+ def initialize(_result_name, _parent_result)
40
+ super
41
+ @graphql_result_data = {}
42
+ end
43
+
44
+ include GraphQLResult
45
+
46
+ attr_accessor :graphql_merged_into
47
+
48
+ def []=(key, value)
49
+ # This is a hack.
50
+ # Basically, this object is merged into the root-level result at some point.
51
+ # But the problem is, some lazies are created whose closures retain reference to _this_
52
+ # object. When those lazies are resolved, they cause an update to this object.
53
+ #
54
+ # In order to return a proper top-level result, we have to update that top-level result object.
55
+ # In order to return a proper partial result (eg, for a directive), we have to update this object, too.
56
+ # Yowza.
57
+ if (t = @graphql_merged_into)
58
+ t[key] = value
59
+ end
60
+
61
+ if value.respond_to?(:graphql_result_data)
62
+ @graphql_result_data[key] = value.graphql_result_data
63
+ # If we encounter some part of this response that requires metadata tracking,
64
+ # then create the metadata hash if necessary. It will be kept up-to-date after this.
65
+ (@graphql_metadata ||= @graphql_result_data.dup)[key] = value
66
+ else
67
+ @graphql_result_data[key] = value
68
+ # keep this up-to-date if it's been initialized
69
+ @graphql_metadata && @graphql_metadata[key] = value
70
+ end
71
+
72
+ value
73
+ end
74
+
75
+ def delete(key)
76
+ @graphql_metadata && @graphql_metadata.delete(key)
77
+ @graphql_result_data.delete(key)
78
+ end
79
+
80
+ def each
81
+ (@graphql_metadata || @graphql_result_data).each { |k, v| yield(k, v) }
82
+ end
83
+
84
+ def values
85
+ (@graphql_metadata || @graphql_result_data).values
86
+ end
87
+
88
+ def key?(k)
89
+ @graphql_result_data.key?(k)
90
+ end
91
+
92
+ def [](k)
93
+ (@graphql_metadata || @graphql_result_data)[k]
94
+ end
95
+ end
96
+
97
+ class GraphQLResultArray
98
+ include GraphQLResult
99
+
100
+ def initialize(_result_name, _parent_result)
101
+ super
102
+ @graphql_result_data = []
103
+ end
104
+
105
+ def graphql_skip_at(index)
106
+ # Mark this index as dead. It's tricky because some indices may already be storing
107
+ # `Lazy`s. So the runtime is still holding indexes _before_ skipping,
108
+ # this object has to coordinate incoming writes to account for any already-skipped indices.
109
+ @skip_indices ||= []
110
+ @skip_indices << index
111
+ offset_by = @skip_indices.count { |skipped_idx| skipped_idx < index}
112
+ delete_at_index = index - offset_by
113
+ @graphql_metadata && @graphql_metadata.delete_at(delete_at_index)
114
+ @graphql_result_data.delete_at(delete_at_index)
115
+ end
116
+
117
+ def []=(idx, value)
118
+ if @skip_indices
119
+ offset_by = @skip_indices.count { |skipped_idx| skipped_idx < idx }
120
+ idx -= offset_by
121
+ end
122
+ if value.respond_to?(:graphql_result_data)
123
+ @graphql_result_data[idx] = value.graphql_result_data
124
+ (@graphql_metadata ||= @graphql_result_data.dup)[idx] = value
125
+ else
126
+ @graphql_result_data[idx] = value
127
+ @graphql_metadata && @graphql_metadata[idx] = value
128
+ end
129
+
130
+ value
131
+ end
132
+
133
+ def values
134
+ (@graphql_metadata || @graphql_result_data)
135
+ end
136
+ end
137
+
138
+ class GraphQLSelectionSet < Hash
139
+ attr_accessor :graphql_directives
140
+ end
141
+
142
+ # @return [GraphQL::Query]
143
+ attr_reader :query
144
+
145
+ # @return [Class<GraphQL::Schema>]
146
+ attr_reader :schema
147
+
148
+ # @return [GraphQL::Query::Context]
149
+ attr_reader :context
150
+
151
+ def thread_info
152
+ info = Thread.current[:__graphql_runtime_info]
153
+ if !info
154
+ new_ti = {}
155
+ info = Thread.current[:__graphql_runtime_info] = new_ti
156
+ end
157
+ info
158
+ end
159
+
160
+ def initialize(query:)
161
+ @query = query
162
+ @dataloader = query.multiplex.dataloader
163
+ @schema = query.schema
164
+ @context = query.context
165
+ @multiplex_context = query.multiplex.context
166
+ # Start this off empty:
167
+ Thread.current[:__graphql_runtime_info] = nil
168
+ @response = GraphQLResultHash.new(nil, nil)
169
+ # Identify runtime directives by checking which of this schema's directives have overridden `def self.resolve`
170
+ @runtime_directive_names = []
171
+ noop_resolve_owner = GraphQL::Schema::Directive.singleton_class
172
+ @schema_directives = schema.directives
173
+ @schema_directives.each do |name, dir_defn|
174
+ if dir_defn.method(:resolve).owner != noop_resolve_owner
175
+ @runtime_directive_names << name
176
+ end
177
+ end
178
+ # A cache of { Class => { String => Schema::Field } }
179
+ # Which assumes that MyObject.get_field("myField") will return the same field
180
+ # during the lifetime of a query
181
+ @fields_cache = Hash.new { |h, k| h[k] = {} }
182
+ # { Class => Boolean }
183
+ @lazy_cache = {}
184
+ end
185
+
186
+ def final_result
187
+ @response && @response.graphql_result_data
188
+ end
189
+
190
+ def inspect
191
+ "#<#{self.class.name} response=#{@response.inspect}>"
192
+ end
193
+
194
+ def tap_or_each(obj_or_array)
195
+ if obj_or_array.is_a?(Array)
196
+ obj_or_array.each do |item|
197
+ yield(item, true)
198
+ end
199
+ else
200
+ yield(obj_or_array, false)
201
+ end
202
+ end
203
+
204
+ # This _begins_ the execution. Some deferred work
205
+ # might be stored up in lazies.
206
+ # @return [void]
207
+ def run_eager
208
+ root_operation = query.selected_operation
209
+ root_op_type = root_operation.operation_type || "query"
210
+ root_type = schema.root_type_for_operation(root_op_type)
211
+ path = []
212
+ set_all_interpreter_context(query.root_value, nil, nil, path)
213
+ object_proxy = authorized_new(root_type, query.root_value, context)
214
+ object_proxy = schema.sync_lazy(object_proxy)
215
+
216
+ if object_proxy.nil?
217
+ # Root .authorized? returned false.
218
+ @response = nil
219
+ else
220
+ call_method_on_directives(:resolve, object_proxy, root_operation.directives) do # execute query level directives
221
+ gathered_selections = gather_selections(object_proxy, root_type, root_operation.selections)
222
+ # This is kind of a hack -- `gathered_selections` is an Array if any of the selections
223
+ # require isolation during execution (because of runtime directives). In that case,
224
+ # make a new, isolated result hash for writing the result into. (That isolated response
225
+ # is eventually merged back into the main response)
226
+ #
227
+ # Otherwise, `gathered_selections` is a hash of selections which can be
228
+ # directly evaluated and the results can be written right into the main response hash.
229
+ tap_or_each(gathered_selections) do |selections, is_selection_array|
230
+ if is_selection_array
231
+ selection_response = GraphQLResultHash.new(nil, nil)
232
+ final_response = @response
233
+ else
234
+ selection_response = @response
235
+ final_response = nil
236
+ end
237
+
238
+ @dataloader.append_job {
239
+ set_all_interpreter_context(query.root_value, nil, nil, path)
240
+ call_method_on_directives(:resolve, object_proxy, selections.graphql_directives) do
241
+ evaluate_selections(
242
+ path,
243
+ object_proxy,
244
+ root_type,
245
+ root_op_type == "mutation",
246
+ selections,
247
+ selection_response,
248
+ final_response,
249
+ nil,
250
+ )
251
+ end
252
+ }
253
+ end
254
+ end
255
+ end
256
+ delete_interpreter_context(:current_path)
257
+ delete_interpreter_context(:current_field)
258
+ delete_interpreter_context(:current_object)
259
+ delete_interpreter_context(:current_arguments)
260
+ nil
261
+ end
262
+
263
+ # @return [void]
264
+ def deep_merge_selection_result(from_result, into_result)
265
+ from_result.each do |key, value|
266
+ if !into_result.key?(key)
267
+ into_result[key] = value
268
+ else
269
+ case value
270
+ when GraphQLResultHash
271
+ deep_merge_selection_result(value, into_result[key])
272
+ else
273
+ # We have to assume that, since this passed the `fields_will_merge` selection,
274
+ # that the old and new values are the same.
275
+ # There's no special handling of arrays because currently, there's no way to split the execution
276
+ # of a list over several concurrent flows.
277
+ into_result[key] = value
278
+ end
279
+ end
280
+ end
281
+ from_result.graphql_merged_into = into_result
282
+ nil
283
+ end
284
+
285
+ def gather_selections(owner_object, owner_type, selections, selections_to_run = nil, selections_by_name = GraphQLSelectionSet.new)
286
+ selections.each do |node|
287
+ # Skip gathering this if the directive says so
288
+ if !directives_include?(node, owner_object, owner_type)
289
+ next
290
+ end
291
+
292
+ if node.is_a?(GraphQL::Language::Nodes::Field)
293
+ response_key = node.alias || node.name
294
+ selections = selections_by_name[response_key]
295
+ # if there was already a selection of this field,
296
+ # use an array to hold all selections,
297
+ # otherise, use the single node to represent the selection
298
+ if selections
299
+ # This field was already selected at least once,
300
+ # add this node to the list of selections
301
+ s = Array(selections)
302
+ s << node
303
+ selections_by_name[response_key] = s
304
+ else
305
+ # No selection was found for this field yet
306
+ selections_by_name[response_key] = node
307
+ end
308
+ else
309
+ # This is an InlineFragment or a FragmentSpread
310
+ if @runtime_directive_names.any? && node.directives.any? { |d| @runtime_directive_names.include?(d.name) }
311
+ next_selections = GraphQLSelectionSet.new
312
+ next_selections.graphql_directives = node.directives
313
+ if selections_to_run
314
+ selections_to_run << next_selections
315
+ else
316
+ selections_to_run = []
317
+ selections_to_run << selections_by_name
318
+ selections_to_run << next_selections
319
+ end
320
+ else
321
+ next_selections = selections_by_name
322
+ end
323
+
324
+ case node
325
+ when GraphQL::Language::Nodes::InlineFragment
326
+ if node.type
327
+ type_defn = schema.get_type(node.type.name, context)
328
+
329
+ # Faster than .map{}.include?()
330
+ query.warden.possible_types(type_defn).each do |t|
331
+ if t == owner_type
332
+ gather_selections(owner_object, owner_type, node.selections, selections_to_run, next_selections)
333
+ break
334
+ end
335
+ end
336
+ else
337
+ # it's an untyped fragment, definitely continue
338
+ gather_selections(owner_object, owner_type, node.selections, selections_to_run, next_selections)
339
+ end
340
+ when GraphQL::Language::Nodes::FragmentSpread
341
+ fragment_def = query.fragments[node.name]
342
+ type_defn = query.get_type(fragment_def.type.name)
343
+ possible_types = query.warden.possible_types(type_defn)
344
+ possible_types.each do |t|
345
+ if t == owner_type
346
+ gather_selections(owner_object, owner_type, fragment_def.selections, selections_to_run, next_selections)
347
+ break
348
+ end
349
+ end
350
+ else
351
+ raise "Invariant: unexpected selection class: #{node.class}"
352
+ end
353
+ end
354
+ end
355
+ selections_to_run || selections_by_name
356
+ end
357
+
358
+ NO_ARGS = {}.freeze
359
+
360
+ # @return [void]
361
+ def evaluate_selections(path, owner_object, owner_type, is_eager_selection, gathered_selections, selections_result, target_result, parent_object) # rubocop:disable Metrics/ParameterLists
362
+ set_all_interpreter_context(owner_object, nil, nil, path)
363
+
364
+ finished_jobs = 0
365
+ enqueued_jobs = gathered_selections.size
366
+ gathered_selections.each do |result_name, field_ast_nodes_or_ast_node|
367
+ @dataloader.append_job {
368
+ evaluate_selection(
369
+ path, result_name, field_ast_nodes_or_ast_node, owner_object, owner_type, is_eager_selection, selections_result, parent_object
370
+ )
371
+ finished_jobs += 1
372
+ if target_result && finished_jobs == enqueued_jobs
373
+ deep_merge_selection_result(selections_result, target_result)
374
+ end
375
+ }
376
+ end
377
+
378
+ selections_result
379
+ end
380
+
381
+ attr_reader :progress_path
382
+
383
+ # @return [void]
384
+ def evaluate_selection(path, result_name, field_ast_nodes_or_ast_node, owner_object, owner_type, is_eager_field, selections_result, parent_object) # rubocop:disable Metrics/ParameterLists
385
+ return if dead_result?(selections_result)
386
+ # As a performance optimization, the hash key will be a `Node` if
387
+ # there's only one selection of the field. But if there are multiple
388
+ # selections of the field, it will be an Array of nodes
389
+ if field_ast_nodes_or_ast_node.is_a?(Array)
390
+ field_ast_nodes = field_ast_nodes_or_ast_node
391
+ ast_node = field_ast_nodes.first
392
+ else
393
+ field_ast_nodes = nil
394
+ ast_node = field_ast_nodes_or_ast_node
395
+ end
396
+ field_name = ast_node.name
397
+ # This can't use `query.get_field` because it gets confused on introspection below if `field_defn` isn't `nil`,
398
+ # because of how `is_introspection` is used to call `.authorized_new` later on.
399
+ field_defn = @fields_cache[owner_type][field_name] ||= owner_type.get_field(field_name, @context)
400
+ is_introspection = false
401
+ if field_defn.nil?
402
+ field_defn = if owner_type == schema.query && (entry_point_field = schema.introspection_system.entry_point(name: field_name))
403
+ is_introspection = true
404
+ entry_point_field
405
+ elsif (dynamic_field = schema.introspection_system.dynamic_field(name: field_name))
406
+ is_introspection = true
407
+ dynamic_field
408
+ else
409
+ raise "Invariant: no field for #{owner_type}.#{field_name}"
410
+ end
411
+ end
412
+ return_type = field_defn.type
413
+
414
+ next_path = path + [result_name]
415
+ next_path.freeze
416
+
417
+ # This seems janky, but we need to know
418
+ # the field's return type at this path in order
419
+ # to propagate `null`
420
+ if return_type.non_null?
421
+ (selections_result.graphql_non_null_field_names ||= []).push(result_name)
422
+ end
423
+ # Set this before calling `run_with_directives`, so that the directive can have the latest path
424
+ set_all_interpreter_context(nil, field_defn, nil, next_path)
425
+ object = owner_object
426
+
427
+ if is_introspection
428
+ object = authorized_new(field_defn.owner, object, context)
429
+ end
430
+
431
+ total_args_count = field_defn.arguments(context).size
432
+ if total_args_count == 0
433
+ resolved_arguments = GraphQL::Execution::Interpreter::Arguments::EMPTY
434
+ evaluate_selection_with_args(resolved_arguments, field_defn, next_path, ast_node, field_ast_nodes, owner_type, object, is_eager_field, result_name, selections_result, parent_object)
435
+ else
436
+ # TODO remove all arguments(...) usages?
437
+ @query.arguments_cache.dataload_for(ast_node, field_defn, object) do |resolved_arguments|
438
+ evaluate_selection_with_args(resolved_arguments, field_defn, next_path, ast_node, field_ast_nodes, owner_type, object, is_eager_field, result_name, selections_result, parent_object)
439
+ end
440
+ end
441
+ end
442
+
443
+ def evaluate_selection_with_args(arguments, field_defn, next_path, ast_node, field_ast_nodes, owner_type, object, is_eager_field, result_name, selection_result, parent_object) # rubocop:disable Metrics/ParameterLists
444
+ return_type = field_defn.type
445
+ after_lazy(arguments, owner: owner_type, field: field_defn, path: next_path, ast_node: ast_node, owner_object: object, arguments: arguments, result_name: result_name, result: selection_result) do |resolved_arguments|
446
+ if resolved_arguments.is_a?(GraphQL::ExecutionError) || resolved_arguments.is_a?(GraphQL::UnauthorizedError)
447
+ continue_value(next_path, resolved_arguments, owner_type, field_defn, return_type.non_null?, ast_node, result_name, selection_result)
448
+ next
449
+ end
450
+
451
+ kwarg_arguments = if resolved_arguments.empty? && field_defn.extras.empty?
452
+ # We can avoid allocating the `{ Symbol => Object }` hash in this case
453
+ NO_ARGS
454
+ else
455
+ # Bundle up the extras, then make a new arguments instance
456
+ # that includes the extras, too.
457
+ extra_args = {}
458
+ field_defn.extras.each do |extra|
459
+ case extra
460
+ when :ast_node
461
+ extra_args[:ast_node] = ast_node
462
+ when :execution_errors
463
+ extra_args[:execution_errors] = ExecutionErrors.new(context, ast_node, next_path)
464
+ when :path
465
+ extra_args[:path] = next_path
466
+ when :lookahead
467
+ if !field_ast_nodes
468
+ field_ast_nodes = [ast_node]
469
+ end
470
+
471
+ extra_args[:lookahead] = Execution::Lookahead.new(
472
+ query: query,
473
+ ast_nodes: field_ast_nodes,
474
+ field: field_defn,
475
+ )
476
+ when :argument_details
477
+ # Use this flag to tell Interpreter::Arguments to add itself
478
+ # to the keyword args hash _before_ freezing everything.
479
+ extra_args[:argument_details] = :__arguments_add_self
480
+ when :parent
481
+ extra_args[:parent] = parent_object
482
+ else
483
+ extra_args[extra] = field_defn.fetch_extra(extra, context)
484
+ end
485
+ end
486
+ if extra_args.any?
487
+ resolved_arguments = resolved_arguments.merge_extras(extra_args)
488
+ end
489
+ resolved_arguments.keyword_arguments
490
+ end
491
+
492
+ set_all_interpreter_context(nil, nil, resolved_arguments, nil)
493
+
494
+ # Optimize for the case that field is selected only once
495
+ if field_ast_nodes.nil? || field_ast_nodes.size == 1
496
+ next_selections = ast_node.selections
497
+ directives = ast_node.directives
498
+ else
499
+ next_selections = []
500
+ directives = []
501
+ field_ast_nodes.each { |f|
502
+ next_selections.concat(f.selections)
503
+ directives.concat(f.directives)
504
+ }
505
+ end
506
+
507
+ field_result = call_method_on_directives(:resolve, object, directives) do
508
+ # Actually call the field resolver and capture the result
509
+ app_result = begin
510
+ query.trace("execute_field", {owner: owner_type, field: field_defn, path: next_path, ast_node: ast_node, query: query, object: object, arguments: kwarg_arguments}) do
511
+ field_defn.resolve(object, kwarg_arguments, context)
512
+ end
513
+ rescue GraphQL::ExecutionError => err
514
+ err
515
+ rescue StandardError => err
516
+ begin
517
+ query.handle_or_reraise(err)
518
+ rescue GraphQL::ExecutionError => ex_err
519
+ ex_err
520
+ end
521
+ end
522
+ after_lazy(app_result, owner: owner_type, field: field_defn, path: next_path, ast_node: ast_node, owner_object: object, arguments: resolved_arguments, result_name: result_name, result: selection_result) do |inner_result|
523
+ continue_value = continue_value(next_path, inner_result, owner_type, field_defn, return_type.non_null?, ast_node, result_name, selection_result)
524
+ if HALT != continue_value
525
+ continue_field(next_path, continue_value, owner_type, field_defn, return_type, ast_node, next_selections, false, object, resolved_arguments, result_name, selection_result)
526
+ end
527
+ end
528
+ end
529
+
530
+ # If this field is a root mutation field, immediately resolve
531
+ # all of its child fields before moving on to the next root mutation field.
532
+ # (Subselections of this mutation will still be resolved level-by-level.)
533
+ if is_eager_field
534
+ Interpreter::Resolve.resolve_all([field_result], @dataloader)
535
+ else
536
+ # Return this from `after_lazy` because it might be another lazy that needs to be resolved
537
+ field_result
538
+ end
539
+ end
540
+ end
541
+
542
+ def dead_result?(selection_result)
543
+ selection_result.graphql_dead || ((parent = selection_result.graphql_parent) && parent.graphql_dead)
544
+ end
545
+
546
+ def set_result(selection_result, result_name, value)
547
+ if !dead_result?(selection_result)
548
+ if value.nil? &&
549
+ ( # there are two conditions under which `nil` is not allowed in the response:
550
+ (selection_result.graphql_non_null_list_items) || # this value would be written into a list that doesn't allow nils
551
+ ((nn = selection_result.graphql_non_null_field_names) && nn.include?(result_name)) # this value would be written into a field that doesn't allow nils
552
+ )
553
+ # This is an invalid nil that should be propagated
554
+ # One caller of this method passes a block,
555
+ # namely when application code returns a `nil` to GraphQL and it doesn't belong there.
556
+ # The other possibility for reaching here is when a field returns an ExecutionError, so we write
557
+ # `nil` to the response, not knowing whether it's an invalid `nil` or not.
558
+ # (And in that case, we don't have to call the schema's handler, since it's not a bug in the application.)
559
+ # TODO the code is trying to tell me something.
560
+ yield if block_given?
561
+ parent = selection_result.graphql_parent
562
+ name_in_parent = selection_result.graphql_result_name
563
+ if parent.nil? # This is a top-level result hash
564
+ @response = nil
565
+ else
566
+ set_result(parent, name_in_parent, nil)
567
+ set_graphql_dead(selection_result)
568
+ end
569
+ else
570
+ selection_result[result_name] = value
571
+ end
572
+ end
573
+ end
574
+
575
+ # Mark this node and any already-registered children as dead,
576
+ # so that it accepts no more writes.
577
+ def set_graphql_dead(selection_result)
578
+ case selection_result
579
+ when GraphQLResultArray
580
+ selection_result.graphql_dead = true
581
+ selection_result.values.each { |v| set_graphql_dead(v) }
582
+ when GraphQLResultHash
583
+ selection_result.graphql_dead = true
584
+ selection_result.each { |k, v| set_graphql_dead(v) }
585
+ else
586
+ # It's a scalar, no way to mark it dead.
587
+ end
588
+ end
589
+
590
+ HALT = Object.new
591
+ def continue_value(path, value, parent_type, field, is_non_null, ast_node, result_name, selection_result) # rubocop:disable Metrics/ParameterLists
592
+ case value
593
+ when nil
594
+ if is_non_null
595
+ set_result(selection_result, result_name, nil) do
596
+ # This block is called if `result_name` is not dead. (Maybe a previous invalid nil caused it be marked dead.)
597
+ err = parent_type::InvalidNullError.new(parent_type, field, value)
598
+ schema.type_error(err, context)
599
+ end
600
+ else
601
+ set_result(selection_result, result_name, nil)
602
+ end
603
+ HALT
604
+ when GraphQL::Error
605
+ # Handle these cases inside a single `when`
606
+ # to avoid the overhead of checking three different classes
607
+ # every time.
608
+ if value.is_a?(GraphQL::ExecutionError)
609
+ if selection_result.nil? || !dead_result?(selection_result)
610
+ value.path ||= path
611
+ value.ast_node ||= ast_node
612
+ context.errors << value
613
+ if selection_result
614
+ set_result(selection_result, result_name, nil)
615
+ end
616
+ end
617
+ HALT
618
+ elsif value.is_a?(GraphQL::UnauthorizedError)
619
+ # this hook might raise & crash, or it might return
620
+ # a replacement value
621
+ next_value = begin
622
+ schema.unauthorized_object(value)
623
+ rescue GraphQL::ExecutionError => err
624
+ err
625
+ end
626
+ continue_value(path, next_value, parent_type, field, is_non_null, ast_node, result_name, selection_result)
627
+ elsif GraphQL::Execution::SKIP == value
628
+ # It's possible a lazy was already written here
629
+ case selection_result
630
+ when GraphQLResultHash
631
+ selection_result.delete(result_name)
632
+ when GraphQLResultArray
633
+ selection_result.graphql_skip_at(result_name)
634
+ when nil
635
+ # this can happen with directives
636
+ else
637
+ raise "Invariant: unexpected result class #{selection_result.class} (#{selection_result.inspect})"
638
+ end
639
+ HALT
640
+ else
641
+ # What could this actually _be_? Anyhow,
642
+ # preserve the default behavior of doing nothing with it.
643
+ value
644
+ end
645
+ when Array
646
+ # It's an array full of execution errors; add them all.
647
+ if value.any? && value.all? { |v| v.is_a?(GraphQL::ExecutionError) }
648
+ list_type_at_all = (field && (field.type.list?))
649
+ if selection_result.nil? || !dead_result?(selection_result)
650
+ value.each_with_index do |error, index|
651
+ error.ast_node ||= ast_node
652
+ error.path ||= path + (list_type_at_all ? [index] : [])
653
+ context.errors << error
654
+ end
655
+ if selection_result
656
+ if list_type_at_all
657
+ result_without_errors = value.map { |v| v.is_a?(GraphQL::ExecutionError) ? nil : v }
658
+ set_result(selection_result, result_name, result_without_errors)
659
+ else
660
+ set_result(selection_result, result_name, nil)
661
+ end
662
+ end
663
+ end
664
+ HALT
665
+ else
666
+ value
667
+ end
668
+ when GraphQL::Execution::Interpreter::RawValue
669
+ # Write raw value directly to the response without resolving nested objects
670
+ set_result(selection_result, result_name, value.resolve)
671
+ HALT
672
+ else
673
+ value
674
+ end
675
+ end
676
+
677
+ # The resolver for `field` returned `value`. Continue to execute the query,
678
+ # treating `value` as `type` (probably the return type of the field).
679
+ #
680
+ # Use `next_selections` to resolve object fields, if there are any.
681
+ #
682
+ # Location information from `path` and `ast_node`.
683
+ #
684
+ # @return [Lazy, Array, Hash, Object] Lazy, Array, and Hash are all traversed to resolve lazy values later
685
+ def continue_field(path, value, owner_type, field, current_type, ast_node, next_selections, is_non_null, owner_object, arguments, result_name, selection_result) # rubocop:disable Metrics/ParameterLists
686
+ if current_type.non_null?
687
+ current_type = current_type.of_type
688
+ is_non_null = true
689
+ end
690
+
691
+ case current_type.kind.name
692
+ when "SCALAR", "ENUM"
693
+ r = begin
694
+ current_type.coerce_result(value, context)
695
+ rescue StandardError => err
696
+ schema.handle_or_reraise(context, err)
697
+ end
698
+ set_result(selection_result, result_name, r)
699
+ r
700
+ when "UNION", "INTERFACE"
701
+ resolved_type_or_lazy = resolve_type(current_type, value, path)
702
+ after_lazy(resolved_type_or_lazy, owner: current_type, path: path, ast_node: ast_node, field: field, owner_object: owner_object, arguments: arguments, trace: false, result_name: result_name, result: selection_result) do |resolved_type_result|
703
+ if resolved_type_result.is_a?(Array) && resolved_type_result.length == 2
704
+ resolved_type, resolved_value = resolved_type_result
705
+ else
706
+ resolved_type = resolved_type_result
707
+ resolved_value = value
708
+ end
709
+
710
+ possible_types = query.possible_types(current_type)
711
+ if !possible_types.include?(resolved_type)
712
+ parent_type = field.owner_type
713
+ err_class = current_type::UnresolvedTypeError
714
+ type_error = err_class.new(resolved_value, field, parent_type, resolved_type, possible_types)
715
+ schema.type_error(type_error, context)
716
+ set_result(selection_result, result_name, nil)
717
+ nil
718
+ else
719
+ continue_field(path, resolved_value, owner_type, field, resolved_type, ast_node, next_selections, is_non_null, owner_object, arguments, result_name, selection_result)
720
+ end
721
+ end
722
+ when "OBJECT"
723
+ object_proxy = begin
724
+ authorized_new(current_type, value, context)
725
+ rescue GraphQL::ExecutionError => err
726
+ err
727
+ end
728
+ after_lazy(object_proxy, owner: current_type, path: path, ast_node: ast_node, field: field, owner_object: owner_object, arguments: arguments, trace: false, result_name: result_name, result: selection_result) do |inner_object|
729
+ continue_value = continue_value(path, inner_object, owner_type, field, is_non_null, ast_node, result_name, selection_result)
730
+ if HALT != continue_value
731
+ response_hash = GraphQLResultHash.new(result_name, selection_result)
732
+ set_result(selection_result, result_name, response_hash)
733
+ gathered_selections = gather_selections(continue_value, current_type, next_selections)
734
+ # There are two possibilities for `gathered_selections`:
735
+ # 1. All selections of this object should be evaluated together (there are no runtime directives modifying execution).
736
+ # This case is handled below, and the result can be written right into the main `response_hash` above.
737
+ # In this case, `gathered_selections` is a hash of selections.
738
+ # 2. Some selections of this object have runtime directives that may or may not modify execution.
739
+ # That part of the selection is evaluated in an isolated way, writing into a sub-response object which is
740
+ # eventually merged into the final response. In this case, `gathered_selections` is an array of things to run in isolation.
741
+ # (Technically, it's possible that one of those entries _doesn't_ require isolation.)
742
+ tap_or_each(gathered_selections) do |selections, is_selection_array|
743
+ if is_selection_array
744
+ this_result = GraphQLResultHash.new(result_name, selection_result)
745
+ final_result = response_hash
746
+ else
747
+ this_result = response_hash
748
+ final_result = nil
749
+ end
750
+ set_all_interpreter_context(continue_value, nil, nil, path) # reset this mutable state
751
+ call_method_on_directives(:resolve, continue_value, selections.graphql_directives) do
752
+ evaluate_selections(
753
+ path,
754
+ continue_value,
755
+ current_type,
756
+ false,
757
+ selections,
758
+ this_result,
759
+ final_result,
760
+ owner_object.object,
761
+ )
762
+ this_result
763
+ end
764
+ end
765
+ end
766
+ end
767
+ when "LIST"
768
+ inner_type = current_type.of_type
769
+ # This is true for objects, unions, and interfaces
770
+ use_dataloader_job = !inner_type.unwrap.kind.input?
771
+ response_list = GraphQLResultArray.new(result_name, selection_result)
772
+ response_list.graphql_non_null_list_items = inner_type.non_null?
773
+ set_result(selection_result, result_name, response_list)
774
+ result_was_set = false
775
+ idx = 0
776
+ list_value = begin
777
+ value.each do |inner_value|
778
+ break if dead_result?(response_list)
779
+ if !result_was_set
780
+ # Don't set the result unless `.each` is successful
781
+ set_result(selection_result, result_name, response_list)
782
+ result_was_set = true
783
+ end
784
+ next_path = path + [idx]
785
+ this_idx = idx
786
+ next_path.freeze
787
+ idx += 1
788
+ if use_dataloader_job
789
+ @dataloader.append_job do
790
+ resolve_list_item(inner_value, inner_type, next_path, ast_node, field, owner_object, arguments, this_idx, response_list, next_selections, owner_type)
791
+ end
792
+ else
793
+ resolve_list_item(inner_value, inner_type, next_path, ast_node, field, owner_object, arguments, this_idx, response_list, next_selections, owner_type)
794
+ end
795
+ end
796
+ # Maybe the list was empty and the block was never called.
797
+ if !result_was_set
798
+ set_result(selection_result, result_name, response_list)
799
+ result_was_set = true
800
+ end
801
+
802
+ response_list
803
+ rescue NoMethodError => err
804
+ # Ruby 2.2 doesn't have NoMethodError#receiver, can't check that one in this case. (It's been EOL since 2017.)
805
+ if err.name == :each && (err.respond_to?(:receiver) ? err.receiver == value : true)
806
+ # This happens when the GraphQL schema doesn't match the implementation. Help the dev debug.
807
+ raise ListResultFailedError.new(value: value, field: field, path: path)
808
+ else
809
+ # This was some other NoMethodError -- let it bubble to reveal the real error.
810
+ raise
811
+ end
812
+ rescue GraphQL::ExecutionError, GraphQL::UnauthorizedError => ex_err
813
+ ex_err
814
+ rescue StandardError => err
815
+ begin
816
+ query.handle_or_reraise(err)
817
+ rescue GraphQL::ExecutionError => ex_err
818
+ ex_err
819
+ end
820
+ end
821
+
822
+ continue_value(path, list_value, owner_type, field, inner_type.non_null?, ast_node, result_name, selection_result)
823
+ else
824
+ raise "Invariant: Unhandled type kind #{current_type.kind} (#{current_type})"
825
+ end
826
+ end
827
+
828
+ def resolve_list_item(inner_value, inner_type, next_path, ast_node, field, owner_object, arguments, this_idx, response_list, next_selections, owner_type) # rubocop:disable Metrics/ParameterLists
829
+ set_all_interpreter_context(nil, nil, nil, next_path)
830
+ call_method_on_directives(:resolve_each, owner_object, ast_node.directives) do
831
+ # This will update `response_list` with the lazy
832
+ after_lazy(inner_value, owner: inner_type, path: next_path, ast_node: ast_node, field: field, owner_object: owner_object, arguments: arguments, result_name: this_idx, result: response_list) do |inner_inner_value|
833
+ continue_value = continue_value(next_path, inner_inner_value, owner_type, field, inner_type.non_null?, ast_node, this_idx, response_list)
834
+ if HALT != continue_value
835
+ continue_field(next_path, continue_value, owner_type, field, inner_type, ast_node, next_selections, false, owner_object, arguments, this_idx, response_list)
836
+ end
837
+ end
838
+ end
839
+ end
840
+
841
+ def call_method_on_directives(method_name, object, directives, &block)
842
+ return yield if directives.nil? || directives.empty?
843
+ run_directive(method_name, object, directives, 0, &block)
844
+ end
845
+
846
+ def run_directive(method_name, object, directives, idx, &block)
847
+ dir_node = directives[idx]
848
+ if !dir_node
849
+ yield
850
+ else
851
+ dir_defn = @schema_directives.fetch(dir_node.name)
852
+ raw_dir_args = arguments(nil, dir_defn, dir_node)
853
+ dir_args = continue_value(
854
+ @context[:current_path], # path
855
+ raw_dir_args, # value
856
+ dir_defn, # parent_type
857
+ nil, # field
858
+ false, # is_non_null
859
+ dir_node, # ast_node
860
+ nil, # result_name
861
+ nil, # selection_result
862
+ )
863
+
864
+ if dir_args == HALT
865
+ nil
866
+ else
867
+ dir_defn.public_send(method_name, object, dir_args, context) do
868
+ run_directive(method_name, object, directives, idx + 1, &block)
869
+ end
870
+ end
871
+ end
872
+ end
873
+
874
+ # Check {Schema::Directive.include?} for each directive that's present
875
+ def directives_include?(node, graphql_object, parent_type)
876
+ node.directives.each do |dir_node|
877
+ dir_defn = @schema_directives.fetch(dir_node.name)
878
+ args = arguments(graphql_object, dir_defn, dir_node)
879
+ if !dir_defn.include?(graphql_object, args, context)
880
+ return false
881
+ end
882
+ end
883
+ true
884
+ end
885
+
886
+ def set_all_interpreter_context(object, field, arguments, path)
887
+ ti = thread_info
888
+ if object
889
+ ti[:current_object] = object
890
+ end
891
+ if field
892
+ ti[:current_field] = field
893
+ end
894
+ if arguments
895
+ ti[:current_arguments] = arguments
896
+ end
897
+ if path
898
+ ti[:current_path] = path
899
+ end
900
+ end
901
+
902
+ # @param obj [Object] Some user-returned value that may want to be batched
903
+ # @param path [Array<String>]
904
+ # @param field [GraphQL::Schema::Field]
905
+ # @param eager [Boolean] Set to `true` for mutation root fields only
906
+ # @param trace [Boolean] If `false`, don't wrap this with field tracing
907
+ # @return [GraphQL::Execution::Lazy, Object] If loading `object` will be deferred, it's a wrapper over it.
908
+ def after_lazy(lazy_obj, owner:, field:, path:, owner_object:, arguments:, ast_node:, result:, result_name:, eager: false, trace: true, &block)
909
+ if lazy?(lazy_obj)
910
+ lazy = GraphQL::Execution::Lazy.new(path: path, field: field) do
911
+ set_all_interpreter_context(owner_object, field, arguments, path)
912
+ # Wrap the execution of _this_ method with tracing,
913
+ # but don't wrap the continuation below
914
+ inner_obj = begin
915
+ if trace
916
+ query.trace("execute_field_lazy", {owner: owner, field: field, path: path, query: query, object: owner_object, arguments: arguments, ast_node: ast_node}) do
917
+ schema.sync_lazy(lazy_obj)
918
+ end
919
+ else
920
+ schema.sync_lazy(lazy_obj)
921
+ end
922
+ rescue GraphQL::ExecutionError, GraphQL::UnauthorizedError => ex_err
923
+ ex_err
924
+ rescue StandardError => err
925
+ begin
926
+ query.handle_or_reraise(err)
927
+ rescue GraphQL::ExecutionError => ex_err
928
+ ex_err
929
+ end
930
+ end
931
+ yield(inner_obj)
932
+ end
933
+
934
+ if eager
935
+ lazy.value
936
+ else
937
+ set_result(result, result_name, lazy)
938
+ lazy
939
+ end
940
+ else
941
+ set_all_interpreter_context(owner_object, field, arguments, path)
942
+ yield(lazy_obj)
943
+ end
944
+ end
945
+
946
+ def arguments(graphql_object, arg_owner, ast_node)
947
+ if arg_owner.arguments_statically_coercible?
948
+ query.arguments_for(ast_node, arg_owner)
949
+ else
950
+ # The arguments must be prepared in the context of the given object
951
+ query.arguments_for(ast_node, arg_owner, parent_object: graphql_object)
952
+ end
953
+ end
954
+
955
+ # Set this pair in the Query context, but also in the interpeter namespace,
956
+ # for compatibility.
957
+ def set_interpreter_context(key, value)
958
+ thread_info[key] = value
959
+ end
960
+
961
+ def delete_interpreter_context(key)
962
+ (ti = thread_info) && ti.delete(key)
963
+ end
964
+
965
+ def resolve_type(type, value, path)
966
+ trace_payload = { context: context, type: type, object: value, path: path }
967
+ resolved_type, resolved_value = query.trace("resolve_type", trace_payload) do
968
+ query.resolve_type(type, value)
969
+ end
970
+
971
+ if lazy?(resolved_type)
972
+ GraphQL::Execution::Lazy.new do
973
+ query.trace("resolve_type_lazy", trace_payload) do
974
+ schema.sync_lazy(resolved_type)
975
+ end
976
+ end
977
+ else
978
+ [resolved_type, resolved_value]
979
+ end
980
+ end
981
+
982
+ def authorized_new(type, value, context)
983
+ type.authorized_new(value, context)
984
+ end
985
+
986
+ def lazy?(object)
987
+ @lazy_cache.fetch(object.class) {
988
+ @lazy_cache[object.class] = @schema.lazy?(object)
989
+ }
990
+ end
991
+ end
992
+ end
993
+ end
994
+ end