graphql_cody 1.13.0

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