graphql 1.12.12 → 2.2.14

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.

Potentially problematic release.


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

Files changed (392) hide show
  1. checksums.yaml +4 -4
  2. data/lib/generators/graphql/core.rb +3 -8
  3. data/lib/generators/graphql/enum_generator.rb +4 -10
  4. data/lib/generators/graphql/field_extractor.rb +31 -0
  5. data/lib/generators/graphql/input_generator.rb +50 -0
  6. data/lib/generators/graphql/install/mutation_root_generator.rb +34 -0
  7. data/lib/generators/graphql/{templates → install/templates}/base_mutation.erb +2 -0
  8. data/lib/generators/graphql/{templates → install/templates}/mutation_type.erb +2 -0
  9. data/lib/generators/graphql/install_generator.rb +14 -4
  10. data/lib/generators/graphql/interface_generator.rb +7 -7
  11. data/lib/generators/graphql/mutation_create_generator.rb +22 -0
  12. data/lib/generators/graphql/mutation_delete_generator.rb +22 -0
  13. data/lib/generators/graphql/mutation_generator.rb +5 -30
  14. data/lib/generators/graphql/mutation_update_generator.rb +22 -0
  15. data/lib/generators/graphql/object_generator.rb +10 -38
  16. data/lib/generators/graphql/orm_mutations_base.rb +40 -0
  17. data/lib/generators/graphql/relay.rb +23 -12
  18. data/lib/generators/graphql/scalar_generator.rb +4 -2
  19. data/lib/generators/graphql/templates/base_argument.erb +2 -0
  20. data/lib/generators/graphql/templates/base_connection.erb +2 -0
  21. data/lib/generators/graphql/templates/base_edge.erb +2 -0
  22. data/lib/generators/graphql/templates/base_enum.erb +2 -0
  23. data/lib/generators/graphql/templates/base_field.erb +2 -0
  24. data/lib/generators/graphql/templates/base_input_object.erb +2 -0
  25. data/lib/generators/graphql/templates/base_interface.erb +2 -0
  26. data/lib/generators/graphql/templates/base_object.erb +2 -0
  27. data/lib/generators/graphql/templates/base_resolver.erb +6 -0
  28. data/lib/generators/graphql/templates/base_scalar.erb +2 -0
  29. data/lib/generators/graphql/templates/base_union.erb +2 -0
  30. data/lib/generators/graphql/templates/enum.erb +5 -1
  31. data/lib/generators/graphql/templates/graphql_controller.erb +2 -0
  32. data/lib/generators/graphql/templates/input.erb +9 -0
  33. data/lib/generators/graphql/templates/interface.erb +4 -2
  34. data/lib/generators/graphql/templates/loader.erb +2 -0
  35. data/lib/generators/graphql/templates/mutation.erb +3 -1
  36. data/lib/generators/graphql/templates/mutation_create.erb +20 -0
  37. data/lib/generators/graphql/templates/mutation_delete.erb +20 -0
  38. data/lib/generators/graphql/templates/mutation_update.erb +21 -0
  39. data/lib/generators/graphql/templates/node_type.erb +2 -0
  40. data/lib/generators/graphql/templates/object.erb +4 -2
  41. data/lib/generators/graphql/templates/query_type.erb +2 -0
  42. data/lib/generators/graphql/templates/scalar.erb +3 -1
  43. data/lib/generators/graphql/templates/schema.erb +19 -2
  44. data/lib/generators/graphql/templates/union.erb +4 -2
  45. data/lib/generators/graphql/type_generator.rb +46 -10
  46. data/lib/generators/graphql/union_generator.rb +5 -5
  47. data/lib/graphql/analysis/ast/analyzer.rb +7 -0
  48. data/lib/graphql/analysis/ast/field_usage.rb +55 -1
  49. data/lib/graphql/analysis/ast/max_query_complexity.rb +0 -1
  50. data/lib/graphql/analysis/ast/query_complexity.rb +88 -140
  51. data/lib/graphql/analysis/ast/query_depth.rb +7 -3
  52. data/lib/graphql/analysis/ast/visitor.rb +50 -42
  53. data/lib/graphql/analysis/ast.rb +26 -23
  54. data/lib/graphql/analysis.rb +0 -7
  55. data/lib/graphql/backtrace/table.rb +4 -22
  56. data/lib/graphql/backtrace/trace.rb +93 -0
  57. data/lib/graphql/backtrace/tracer.rb +8 -6
  58. data/lib/graphql/backtrace.rb +3 -8
  59. data/lib/graphql/coercion_error.rb +1 -9
  60. data/lib/graphql/dataloader/async_dataloader.rb +85 -0
  61. data/lib/graphql/dataloader/null_dataloader.rb +3 -1
  62. data/lib/graphql/dataloader/request.rb +5 -0
  63. data/lib/graphql/dataloader/source.rb +120 -31
  64. data/lib/graphql/dataloader.rb +168 -142
  65. data/lib/graphql/date_encoding_error.rb +16 -0
  66. data/lib/graphql/dig.rb +1 -1
  67. data/lib/graphql/duration_encoding_error.rb +16 -0
  68. data/lib/graphql/execution/errors.rb +12 -81
  69. data/lib/graphql/execution/interpreter/arguments.rb +2 -2
  70. data/lib/graphql/execution/interpreter/arguments_cache.rb +36 -34
  71. data/lib/graphql/execution/interpreter/resolve.rb +32 -2
  72. data/lib/graphql/execution/interpreter/runtime/graphql_result.rb +170 -0
  73. data/lib/graphql/execution/interpreter/runtime.rb +414 -341
  74. data/lib/graphql/execution/interpreter.rb +122 -80
  75. data/lib/graphql/execution/lazy.rb +11 -21
  76. data/lib/graphql/execution/lookahead.rb +125 -54
  77. data/lib/graphql/execution/multiplex.rb +4 -172
  78. data/lib/graphql/execution.rb +11 -4
  79. data/lib/graphql/integer_encoding_error.rb +18 -2
  80. data/lib/graphql/introspection/directive_location_enum.rb +2 -2
  81. data/lib/graphql/introspection/directive_type.rb +5 -3
  82. data/lib/graphql/introspection/dynamic_fields.rb +3 -8
  83. data/lib/graphql/introspection/entry_points.rb +11 -18
  84. data/lib/graphql/introspection/enum_value_type.rb +2 -2
  85. data/lib/graphql/introspection/field_type.rb +3 -3
  86. data/lib/graphql/introspection/input_value_type.rb +10 -4
  87. data/lib/graphql/introspection/schema_type.rb +12 -5
  88. data/lib/graphql/introspection/type_type.rb +25 -12
  89. data/lib/graphql/introspection.rb +6 -2
  90. data/lib/graphql/language/block_string.rb +37 -25
  91. data/lib/graphql/language/definition_slice.rb +1 -1
  92. data/lib/graphql/language/document_from_schema_definition.rb +78 -65
  93. data/lib/graphql/language/lexer.rb +345 -1467
  94. data/lib/graphql/language/nodes.rb +145 -91
  95. data/lib/graphql/language/parser.rb +701 -1921
  96. data/lib/graphql/language/printer.rb +351 -155
  97. data/lib/graphql/language/sanitized_printer.rb +25 -27
  98. data/lib/graphql/language/static_visitor.rb +167 -0
  99. data/lib/graphql/language/token.rb +0 -4
  100. data/lib/graphql/language/visitor.rb +188 -141
  101. data/lib/graphql/language.rb +1 -0
  102. data/lib/graphql/load_application_object_failed_error.rb +5 -1
  103. data/lib/graphql/name_validator.rb +0 -4
  104. data/lib/graphql/pagination/active_record_relation_connection.rb +37 -8
  105. data/lib/graphql/pagination/array_connection.rb +8 -6
  106. data/lib/graphql/pagination/connection.rb +61 -7
  107. data/lib/graphql/pagination/connections.rb +22 -23
  108. data/lib/graphql/pagination/mongoid_relation_connection.rb +1 -2
  109. data/lib/graphql/pagination/relation_connection.rb +60 -28
  110. data/lib/graphql/query/context/scoped_context.rb +101 -0
  111. data/lib/graphql/query/context.rb +109 -189
  112. data/lib/graphql/query/input_validation_result.rb +10 -1
  113. data/lib/graphql/query/null_context.rb +14 -29
  114. data/lib/graphql/query/validation_pipeline.rb +15 -39
  115. data/lib/graphql/query/variable_validation_error.rb +2 -2
  116. data/lib/graphql/query/variables.rb +35 -17
  117. data/lib/graphql/query.rb +78 -65
  118. data/lib/graphql/railtie.rb +8 -109
  119. data/lib/graphql/rake_task/validate.rb +1 -1
  120. data/lib/graphql/rake_task.rb +30 -11
  121. data/lib/graphql/relay/range_add.rb +9 -16
  122. data/lib/graphql/relay.rb +0 -15
  123. data/lib/graphql/rubocop/graphql/base_cop.rb +36 -0
  124. data/lib/graphql/rubocop/graphql/default_null_true.rb +43 -0
  125. data/lib/graphql/rubocop/graphql/default_required_true.rb +43 -0
  126. data/lib/graphql/rubocop.rb +4 -0
  127. data/lib/graphql/schema/addition.rb +78 -45
  128. data/lib/graphql/schema/always_visible.rb +10 -0
  129. data/lib/graphql/schema/argument.rb +134 -80
  130. data/lib/graphql/schema/base_64_encoder.rb +3 -5
  131. data/lib/graphql/schema/build_from_definition.rb +60 -38
  132. data/lib/graphql/schema/directive/feature.rb +1 -1
  133. data/lib/graphql/schema/directive/flagged.rb +2 -2
  134. data/lib/graphql/schema/directive/include.rb +1 -1
  135. data/lib/graphql/schema/directive/one_of.rb +24 -0
  136. data/lib/graphql/schema/directive/skip.rb +1 -1
  137. data/lib/graphql/schema/directive/specified_by.rb +14 -0
  138. data/lib/graphql/schema/directive/transform.rb +2 -2
  139. data/lib/graphql/schema/directive.rb +33 -21
  140. data/lib/graphql/schema/enum.rb +93 -46
  141. data/lib/graphql/schema/enum_value.rb +4 -21
  142. data/lib/graphql/schema/field/connection_extension.rb +6 -16
  143. data/lib/graphql/schema/field/scope_extension.rb +8 -1
  144. data/lib/graphql/schema/field.rb +432 -337
  145. data/lib/graphql/schema/field_extension.rb +86 -2
  146. data/lib/graphql/schema/find_inherited_value.rb +3 -7
  147. data/lib/graphql/schema/finder.rb +5 -5
  148. data/lib/graphql/schema/has_single_input_argument.rb +156 -0
  149. data/lib/graphql/schema/input_object.rb +88 -90
  150. data/lib/graphql/schema/interface.rb +19 -59
  151. data/lib/graphql/schema/introspection_system.rb +6 -9
  152. data/lib/graphql/schema/late_bound_type.rb +8 -2
  153. data/lib/graphql/schema/list.rb +18 -7
  154. data/lib/graphql/schema/loader.rb +3 -3
  155. data/lib/graphql/schema/member/base_dsl_methods.rb +18 -19
  156. data/lib/graphql/schema/member/build_type.rb +16 -13
  157. data/lib/graphql/schema/member/has_arguments.rb +288 -84
  158. data/lib/graphql/schema/member/has_ast_node.rb +12 -0
  159. data/lib/graphql/schema/member/has_deprecation_reason.rb +3 -4
  160. data/lib/graphql/schema/member/has_directives.rb +81 -61
  161. data/lib/graphql/schema/member/has_fields.rb +149 -31
  162. data/lib/graphql/schema/member/has_interfaces.rb +143 -0
  163. data/lib/graphql/schema/member/has_validators.rb +32 -6
  164. data/lib/graphql/schema/member/relay_shortcuts.rb +47 -2
  165. data/lib/graphql/schema/member/scoped.rb +19 -0
  166. data/lib/graphql/schema/member/type_system_helpers.rb +17 -0
  167. data/lib/graphql/schema/member/validates_input.rb +6 -6
  168. data/lib/graphql/schema/member.rb +1 -6
  169. data/lib/graphql/schema/mutation.rb +0 -9
  170. data/lib/graphql/schema/non_null.rb +7 -7
  171. data/lib/graphql/schema/object.rb +30 -119
  172. data/lib/graphql/schema/printer.rb +23 -25
  173. data/lib/graphql/schema/relay_classic_mutation.rb +13 -90
  174. data/lib/graphql/schema/resolver/has_payload_type.rb +46 -11
  175. data/lib/graphql/schema/resolver.rb +101 -102
  176. data/lib/graphql/schema/scalar.rb +20 -21
  177. data/lib/graphql/schema/subscription.rb +45 -17
  178. data/lib/graphql/schema/timeout.rb +25 -29
  179. data/lib/graphql/schema/type_expression.rb +1 -1
  180. data/lib/graphql/schema/type_membership.rb +21 -4
  181. data/lib/graphql/schema/union.rb +15 -15
  182. data/lib/graphql/schema/unique_within_type.rb +1 -1
  183. data/lib/graphql/schema/validator/allow_blank_validator.rb +29 -0
  184. data/lib/graphql/schema/validator/allow_null_validator.rb +26 -0
  185. data/lib/graphql/schema/validator/exclusion_validator.rb +3 -1
  186. data/lib/graphql/schema/validator/format_validator.rb +4 -5
  187. data/lib/graphql/schema/validator/inclusion_validator.rb +3 -1
  188. data/lib/graphql/schema/validator/length_validator.rb +5 -3
  189. data/lib/graphql/schema/validator/numericality_validator.rb +13 -2
  190. data/lib/graphql/schema/validator/required_validator.rb +29 -15
  191. data/lib/graphql/schema/validator.rb +35 -27
  192. data/lib/graphql/schema/warden.rb +259 -132
  193. data/lib/graphql/schema/wrapper.rb +0 -5
  194. data/lib/graphql/schema.rb +658 -989
  195. data/lib/graphql/static_validation/all_rules.rb +3 -1
  196. data/lib/graphql/static_validation/base_visitor.rb +14 -28
  197. data/lib/graphql/static_validation/definition_dependencies.rb +7 -2
  198. data/lib/graphql/static_validation/error.rb +3 -1
  199. data/lib/graphql/static_validation/literal_validator.rb +21 -4
  200. data/lib/graphql/static_validation/rules/argument_literals_are_compatible.rb +1 -1
  201. data/lib/graphql/static_validation/rules/arguments_are_defined.rb +1 -1
  202. data/lib/graphql/static_validation/rules/directives_are_defined.rb +11 -5
  203. data/lib/graphql/static_validation/rules/directives_are_in_valid_locations.rb +13 -13
  204. data/lib/graphql/static_validation/rules/fields_have_appropriate_selections.rb +12 -4
  205. data/lib/graphql/static_validation/rules/fields_will_merge.rb +54 -28
  206. data/lib/graphql/static_validation/rules/fields_will_merge_error.rb +25 -4
  207. data/lib/graphql/static_validation/rules/fragments_are_finite.rb +2 -2
  208. data/lib/graphql/static_validation/rules/one_of_input_objects_are_valid.rb +66 -0
  209. data/lib/graphql/static_validation/rules/one_of_input_objects_are_valid_error.rb +29 -0
  210. data/lib/graphql/static_validation/rules/query_root_exists.rb +17 -0
  211. data/lib/graphql/static_validation/rules/query_root_exists_error.rb +26 -0
  212. data/lib/graphql/static_validation/rules/required_arguments_are_present.rb +5 -3
  213. data/lib/graphql/static_validation/rules/required_input_object_attributes_are_present.rb +4 -4
  214. data/lib/graphql/static_validation/rules/unique_directives_per_location.rb +13 -7
  215. data/lib/graphql/static_validation/rules/variable_default_values_are_correctly_typed.rb +1 -1
  216. data/lib/graphql/static_validation/rules/variable_usages_are_allowed.rb +13 -7
  217. data/lib/graphql/static_validation/validation_context.rb +16 -6
  218. data/lib/graphql/static_validation/validator.rb +11 -27
  219. data/lib/graphql/static_validation.rb +0 -3
  220. data/lib/graphql/string_encoding_error.rb +13 -3
  221. data/lib/graphql/subscriptions/action_cable_subscriptions.rb +46 -9
  222. data/lib/graphql/subscriptions/default_subscription_resolve_extension.rb +38 -1
  223. data/lib/graphql/subscriptions/event.rb +75 -37
  224. data/lib/graphql/subscriptions/serialize.rb +25 -3
  225. data/lib/graphql/subscriptions.rb +59 -47
  226. data/lib/graphql/testing/helpers.rb +129 -0
  227. data/lib/graphql/testing.rb +2 -0
  228. data/lib/graphql/tracing/active_support_notifications_trace.rb +16 -0
  229. data/lib/graphql/tracing/active_support_notifications_tracing.rb +6 -20
  230. data/lib/graphql/tracing/appoptics_trace.rb +251 -0
  231. data/lib/graphql/tracing/appoptics_tracing.rb +2 -2
  232. data/lib/graphql/tracing/appsignal_trace.rb +77 -0
  233. data/lib/graphql/tracing/appsignal_tracing.rb +15 -0
  234. data/lib/graphql/tracing/data_dog_trace.rb +183 -0
  235. data/lib/graphql/tracing/data_dog_tracing.rb +25 -15
  236. data/lib/graphql/{execution/instrumentation.rb → tracing/legacy_hooks_trace.rb} +10 -28
  237. data/lib/graphql/tracing/legacy_trace.rb +69 -0
  238. data/lib/graphql/tracing/new_relic_trace.rb +75 -0
  239. data/lib/graphql/tracing/notifications_trace.rb +45 -0
  240. data/lib/graphql/tracing/notifications_tracing.rb +59 -0
  241. data/lib/graphql/tracing/platform_trace.rb +118 -0
  242. data/lib/graphql/tracing/platform_tracing.rb +46 -49
  243. data/lib/graphql/tracing/{prometheus_tracing → prometheus_trace}/graphql_collector.rb +4 -2
  244. data/lib/graphql/tracing/prometheus_trace.rb +89 -0
  245. data/lib/graphql/tracing/prometheus_tracing.rb +3 -3
  246. data/lib/graphql/tracing/scout_trace.rb +72 -0
  247. data/lib/graphql/tracing/sentry_trace.rb +112 -0
  248. data/lib/graphql/tracing/statsd_trace.rb +56 -0
  249. data/lib/graphql/tracing/trace.rb +76 -0
  250. data/lib/graphql/tracing.rb +20 -41
  251. data/lib/graphql/type_kinds.rb +6 -3
  252. data/lib/graphql/types/big_int.rb +5 -1
  253. data/lib/graphql/types/int.rb +1 -1
  254. data/lib/graphql/types/iso_8601_date.rb +17 -6
  255. data/lib/graphql/types/iso_8601_date_time.rb +12 -1
  256. data/lib/graphql/types/iso_8601_duration.rb +77 -0
  257. data/lib/graphql/types/relay/base_connection.rb +16 -6
  258. data/lib/graphql/types/relay/connection_behaviors.rb +82 -32
  259. data/lib/graphql/types/relay/edge_behaviors.rb +36 -7
  260. data/lib/graphql/types/relay/has_node_field.rb +2 -2
  261. data/lib/graphql/types/relay/has_nodes_field.rb +2 -2
  262. data/lib/graphql/types/relay/node_behaviors.rb +12 -2
  263. data/lib/graphql/types/relay/page_info_behaviors.rb +7 -2
  264. data/lib/graphql/types/relay.rb +0 -3
  265. data/lib/graphql/types/string.rb +2 -2
  266. data/lib/graphql/types.rb +1 -0
  267. data/lib/graphql/unauthorized_error.rb +1 -1
  268. data/lib/graphql/version.rb +1 -1
  269. data/lib/graphql.rb +33 -95
  270. data/readme.md +13 -6
  271. metadata +102 -185
  272. data/lib/graphql/analysis/analyze_query.rb +0 -98
  273. data/lib/graphql/analysis/field_usage.rb +0 -45
  274. data/lib/graphql/analysis/max_query_complexity.rb +0 -26
  275. data/lib/graphql/analysis/max_query_depth.rb +0 -26
  276. data/lib/graphql/analysis/query_complexity.rb +0 -88
  277. data/lib/graphql/analysis/query_depth.rb +0 -43
  278. data/lib/graphql/analysis/reducer_state.rb +0 -48
  279. data/lib/graphql/argument.rb +0 -131
  280. data/lib/graphql/authorization.rb +0 -82
  281. data/lib/graphql/backtrace/legacy_tracer.rb +0 -56
  282. data/lib/graphql/backwards_compatibility.rb +0 -61
  283. data/lib/graphql/base_type.rb +0 -230
  284. data/lib/graphql/boolean_type.rb +0 -2
  285. data/lib/graphql/compatibility/execution_specification/counter_schema.rb +0 -53
  286. data/lib/graphql/compatibility/execution_specification/specification_schema.rb +0 -200
  287. data/lib/graphql/compatibility/execution_specification.rb +0 -436
  288. data/lib/graphql/compatibility/lazy_execution_specification/lazy_schema.rb +0 -111
  289. data/lib/graphql/compatibility/lazy_execution_specification.rb +0 -215
  290. data/lib/graphql/compatibility/query_parser_specification/parse_error_specification.rb +0 -87
  291. data/lib/graphql/compatibility/query_parser_specification/query_assertions.rb +0 -79
  292. data/lib/graphql/compatibility/query_parser_specification.rb +0 -266
  293. data/lib/graphql/compatibility/schema_parser_specification.rb +0 -682
  294. data/lib/graphql/compatibility.rb +0 -5
  295. data/lib/graphql/define/assign_argument.rb +0 -12
  296. data/lib/graphql/define/assign_connection.rb +0 -13
  297. data/lib/graphql/define/assign_enum_value.rb +0 -18
  298. data/lib/graphql/define/assign_global_id_field.rb +0 -11
  299. data/lib/graphql/define/assign_mutation_function.rb +0 -34
  300. data/lib/graphql/define/assign_object_field.rb +0 -42
  301. data/lib/graphql/define/defined_object_proxy.rb +0 -53
  302. data/lib/graphql/define/instance_definable.rb +0 -240
  303. data/lib/graphql/define/no_definition_error.rb +0 -7
  304. data/lib/graphql/define/non_null_with_bang.rb +0 -16
  305. data/lib/graphql/define/type_definer.rb +0 -31
  306. data/lib/graphql/define.rb +0 -31
  307. data/lib/graphql/deprecated_dsl.rb +0 -47
  308. data/lib/graphql/deprecation.rb +0 -13
  309. data/lib/graphql/directive/deprecated_directive.rb +0 -2
  310. data/lib/graphql/directive/include_directive.rb +0 -2
  311. data/lib/graphql/directive/skip_directive.rb +0 -2
  312. data/lib/graphql/directive.rb +0 -111
  313. data/lib/graphql/enum_type.rb +0 -129
  314. data/lib/graphql/execution/execute.rb +0 -333
  315. data/lib/graphql/execution/flatten.rb +0 -40
  316. data/lib/graphql/execution/lazy/resolve.rb +0 -91
  317. data/lib/graphql/execution/typecast.rb +0 -50
  318. data/lib/graphql/field/resolve.rb +0 -59
  319. data/lib/graphql/field.rb +0 -226
  320. data/lib/graphql/filter.rb +0 -53
  321. data/lib/graphql/float_type.rb +0 -2
  322. data/lib/graphql/function.rb +0 -128
  323. data/lib/graphql/id_type.rb +0 -2
  324. data/lib/graphql/input_object_type.rb +0 -138
  325. data/lib/graphql/int_type.rb +0 -2
  326. data/lib/graphql/interface_type.rb +0 -72
  327. data/lib/graphql/internal_representation/document.rb +0 -27
  328. data/lib/graphql/internal_representation/node.rb +0 -206
  329. data/lib/graphql/internal_representation/print.rb +0 -51
  330. data/lib/graphql/internal_representation/rewrite.rb +0 -184
  331. data/lib/graphql/internal_representation/scope.rb +0 -88
  332. data/lib/graphql/internal_representation/visit.rb +0 -36
  333. data/lib/graphql/internal_representation.rb +0 -7
  334. data/lib/graphql/language/lexer.rl +0 -262
  335. data/lib/graphql/language/parser.y +0 -543
  336. data/lib/graphql/list_type.rb +0 -80
  337. data/lib/graphql/non_null_type.rb +0 -71
  338. data/lib/graphql/object_type.rb +0 -130
  339. data/lib/graphql/query/arguments.rb +0 -189
  340. data/lib/graphql/query/arguments_cache.rb +0 -24
  341. data/lib/graphql/query/executor.rb +0 -52
  342. data/lib/graphql/query/literal_input.rb +0 -136
  343. data/lib/graphql/query/serial_execution/field_resolution.rb +0 -92
  344. data/lib/graphql/query/serial_execution/operation_resolution.rb +0 -19
  345. data/lib/graphql/query/serial_execution/selection_resolution.rb +0 -23
  346. data/lib/graphql/query/serial_execution/value_resolution.rb +0 -87
  347. data/lib/graphql/query/serial_execution.rb +0 -40
  348. data/lib/graphql/relay/array_connection.rb +0 -83
  349. data/lib/graphql/relay/base_connection.rb +0 -189
  350. data/lib/graphql/relay/connection_instrumentation.rb +0 -54
  351. data/lib/graphql/relay/connection_resolve.rb +0 -43
  352. data/lib/graphql/relay/connection_type.rb +0 -41
  353. data/lib/graphql/relay/edge.rb +0 -27
  354. data/lib/graphql/relay/edge_type.rb +0 -19
  355. data/lib/graphql/relay/edges_instrumentation.rb +0 -40
  356. data/lib/graphql/relay/global_id_resolve.rb +0 -18
  357. data/lib/graphql/relay/mongo_relation_connection.rb +0 -50
  358. data/lib/graphql/relay/mutation/instrumentation.rb +0 -23
  359. data/lib/graphql/relay/mutation/resolve.rb +0 -56
  360. data/lib/graphql/relay/mutation/result.rb +0 -38
  361. data/lib/graphql/relay/mutation.rb +0 -106
  362. data/lib/graphql/relay/node.rb +0 -39
  363. data/lib/graphql/relay/page_info.rb +0 -7
  364. data/lib/graphql/relay/relation_connection.rb +0 -188
  365. data/lib/graphql/relay/type_extensions.rb +0 -32
  366. data/lib/graphql/scalar_type.rb +0 -91
  367. data/lib/graphql/schema/base_64_bp.rb +0 -26
  368. data/lib/graphql/schema/catchall_middleware.rb +0 -35
  369. data/lib/graphql/schema/default_parse_error.rb +0 -10
  370. data/lib/graphql/schema/default_type_error.rb +0 -17
  371. data/lib/graphql/schema/member/accepts_definition.rb +0 -152
  372. data/lib/graphql/schema/member/cached_graphql_definition.rb +0 -31
  373. data/lib/graphql/schema/member/instrumentation.rb +0 -131
  374. data/lib/graphql/schema/middleware_chain.rb +0 -82
  375. data/lib/graphql/schema/possible_types.rb +0 -44
  376. data/lib/graphql/schema/rescue_middleware.rb +0 -60
  377. data/lib/graphql/schema/timeout_middleware.rb +0 -88
  378. data/lib/graphql/schema/traversal.rb +0 -228
  379. data/lib/graphql/schema/validation.rb +0 -313
  380. data/lib/graphql/static_validation/default_visitor.rb +0 -15
  381. data/lib/graphql/static_validation/no_validate_visitor.rb +0 -10
  382. data/lib/graphql/static_validation/type_stack.rb +0 -216
  383. data/lib/graphql/string_type.rb +0 -2
  384. data/lib/graphql/subscriptions/instrumentation.rb +0 -79
  385. data/lib/graphql/subscriptions/subscription_root.rb +0 -76
  386. data/lib/graphql/tracing/skylight_tracing.rb +0 -70
  387. data/lib/graphql/types/relay/default_relay.rb +0 -27
  388. data/lib/graphql/types/relay/node_field.rb +0 -25
  389. data/lib/graphql/types/relay/nodes_field.rb +0 -27
  390. data/lib/graphql/union_type.rb +0 -115
  391. data/lib/graphql/upgrader/member.rb +0 -937
  392. data/lib/graphql/upgrader/schema.rb +0 -38
@@ -11,98 +11,140 @@ require "graphql/execution/interpreter/handles_raw_value"
11
11
  module GraphQL
12
12
  module Execution
13
13
  class Interpreter
14
- def initialize
15
- end
14
+ class << self
15
+ # Used internally to signal that the query shouldn't be executed
16
+ # @api private
17
+ NO_OPERATION = GraphQL::EmptyObjects::EMPTY_HASH
16
18
 
17
- # Support `Executor` :S
18
- def execute(_operation, _root_type, query)
19
- runtime = evaluate(query)
20
- sync_lazies(query: query)
21
- runtime.response
22
- end
19
+ # @param schema [GraphQL::Schema]
20
+ # @param queries [Array<GraphQL::Query, Hash>]
21
+ # @param context [Hash]
22
+ # @param max_complexity [Integer, nil]
23
+ # @return [Array<Hash>] One result per query
24
+ def run_all(schema, query_options, context: {}, max_complexity: schema.max_complexity)
25
+ queries = query_options.map do |opts|
26
+ case opts
27
+ when Hash
28
+ schema.query_class.new(schema, nil, **opts)
29
+ when GraphQL::Query
30
+ opts
31
+ else
32
+ raise "Expected Hash or GraphQL::Query, not #{opts.class} (#{opts.inspect})"
33
+ end
34
+ end
23
35
 
24
- def self.use(schema_class)
25
- if schema_class.interpreter?
26
- definition_line = caller(2, 1).first
27
- GraphQL::Deprecation.warn("GraphQL::Execution::Interpreter is now the default; remove `use GraphQL::Execution::Interpreter` from the schema definition (#{definition_line})")
28
- else
29
- schema_class.query_execution_strategy(self)
30
- schema_class.mutation_execution_strategy(self)
31
- schema_class.subscription_execution_strategy(self)
32
- schema_class.add_subscription_extension_if_necessary
33
- end
34
- end
36
+ multiplex = Execution::Multiplex.new(schema: schema, queries: queries, context: context, max_complexity: max_complexity)
37
+ multiplex.current_trace.execute_multiplex(multiplex: multiplex) do
38
+ schema = multiplex.schema
39
+ queries = multiplex.queries
40
+ lazies_at_depth = Hash.new { |h, k| h[k] = [] }
41
+ multiplex_analyzers = schema.multiplex_analyzers
42
+ if multiplex.max_complexity
43
+ multiplex_analyzers += [GraphQL::Analysis::AST::MaxQueryComplexity]
44
+ end
35
45
 
36
- def self.begin_multiplex(multiplex)
37
- # Since this is basically the batching context,
38
- # share it for a whole multiplex
39
- multiplex.context[:interpreter_instance] ||= self.new
40
- end
46
+ schema.analysis_engine.analyze_multiplex(multiplex, multiplex_analyzers)
47
+ begin
48
+ # Since this is basically the batching context,
49
+ # share it for a whole multiplex
50
+ multiplex.context[:interpreter_instance] ||= multiplex.schema.query_execution_strategy(deprecation_warning: false).new
51
+ # Do as much eager evaluation of the query as possible
52
+ results = []
53
+ queries.each_with_index do |query, idx|
54
+ if query.subscription? && !query.subscription_update?
55
+ query.context.namespace(:subscriptions)[:events] = []
56
+ end
57
+ multiplex.dataloader.append_job {
58
+ operation = query.selected_operation
59
+ result = if operation.nil? || !query.valid? || query.context.errors.any?
60
+ NO_OPERATION
61
+ else
62
+ begin
63
+ # Although queries in a multiplex _share_ an Interpreter instance,
64
+ # they also have another item of state, which is private to that query
65
+ # in particular, assign it here:
66
+ runtime = Runtime.new(query: query, lazies_at_depth: lazies_at_depth)
67
+ query.context.namespace(:interpreter_runtime)[:runtime] = runtime
41
68
 
42
- def self.begin_query(query, multiplex)
43
- # The batching context is shared by the multiplex,
44
- # so fetch it out and use that instance.
45
- interpreter =
46
- query.context.namespace(:interpreter)[:interpreter_instance] =
47
- multiplex.context[:interpreter_instance]
48
- interpreter.evaluate(query)
49
- query
50
- end
69
+ query.current_trace.execute_query(query: query) do
70
+ runtime.run_eager
71
+ end
72
+ rescue GraphQL::ExecutionError => err
73
+ query.context.errors << err
74
+ NO_OPERATION
75
+ end
76
+ end
77
+ results[idx] = result
78
+ }
79
+ end
51
80
 
52
- def self.finish_multiplex(_results, multiplex)
53
- interpreter = multiplex.context[:interpreter_instance]
54
- interpreter.sync_lazies(multiplex: multiplex)
55
- end
81
+ multiplex.dataloader.run
56
82
 
57
- def self.finish_query(query, _multiplex)
58
- {
59
- "data" => query.context.namespace(:interpreter)[:runtime].response
60
- }
61
- end
83
+ # Then, work through lazy results in a breadth-first way
84
+ multiplex.dataloader.append_job {
85
+ query = multiplex.queries.length == 1 ? multiplex.queries[0] : nil
86
+ queries = multiplex ? multiplex.queries : [query]
87
+ final_values = queries.map do |query|
88
+ runtime = query.context.namespace(:interpreter_runtime)[:runtime]
89
+ # it might not be present if the query has an error
90
+ runtime ? runtime.final_result : nil
91
+ end
92
+ final_values.compact!
93
+ multiplex.current_trace.execute_query_lazy(multiplex: multiplex, query: query) do
94
+ Interpreter::Resolve.resolve_each_depth(lazies_at_depth, multiplex.dataloader)
95
+ end
96
+ }
97
+ multiplex.dataloader.run
62
98
 
63
- # Run the eager part of `query`
64
- # @return {Interpreter::Runtime}
65
- def evaluate(query)
66
- # Although queries in a multiplex _share_ an Interpreter instance,
67
- # they also have another item of state, which is private to that query
68
- # in particular, assign it here:
69
- runtime = Runtime.new(query: query)
70
- query.context.namespace(:interpreter)[:runtime] = runtime
99
+ # Then, find all errors and assign the result to the query object
100
+ results.each_with_index do |data_result, idx|
101
+ query = queries[idx]
102
+ if (events = query.context.namespace(:subscriptions)[:events]) && events.any?
103
+ schema.subscriptions.write_subscription(query, events)
104
+ end
105
+ # Assign the result so that it can be accessed in instrumentation
106
+ query.result_values = if data_result.equal?(NO_OPERATION)
107
+ if !query.valid? || query.context.errors.any?
108
+ # A bit weird, but `Query#static_errors` _includes_ `query.context.errors`
109
+ { "errors" => query.static_errors.map(&:to_h) }
110
+ else
111
+ data_result
112
+ end
113
+ else
114
+ result = {}
71
115
 
72
- query.trace("execute_query", {query: query}) do
73
- runtime.run_eager
74
- end
116
+ if query.context.errors.any?
117
+ error_result = query.context.errors.map(&:to_h)
118
+ result["errors"] = error_result
119
+ end
75
120
 
76
- runtime
77
- end
121
+ result["data"] = query.context.namespace(:interpreter_runtime)[:runtime].final_result
78
122
 
79
- # Run the lazy part of `query` or `multiplex`.
80
- # @return [void]
81
- def sync_lazies(query: nil, multiplex: nil)
82
- tracer = query || multiplex
83
- if query.nil? && multiplex.queries.length == 1
84
- query = multiplex.queries[0]
85
- end
86
- queries = multiplex ? multiplex.queries : [query]
87
- final_values = queries.map do |query|
88
- runtime = query.context.namespace(:interpreter)[:runtime]
89
- # it might not be present if the query has an error
90
- runtime ? runtime.response : nil
91
- end
92
- final_values.compact!
93
- tracer.trace("execute_query_lazy", {multiplex: multiplex, query: query}) do
94
- Interpreter::Resolve.resolve_all(final_values, multiplex.dataloader)
95
- end
96
- queries.each do |query|
97
- runtime = query.context.namespace(:interpreter)[:runtime]
98
- if runtime
99
- runtime.delete_interpreter_context(:current_path)
100
- runtime.delete_interpreter_context(:current_field)
101
- runtime.delete_interpreter_context(:current_object)
102
- runtime.delete_interpreter_context(:current_arguments)
123
+ result
124
+ end
125
+ if query.context.namespace?(:__query_result_extensions__)
126
+ query.result_values["extensions"] = query.context.namespace(:__query_result_extensions__)
127
+ end
128
+ # Get the Query::Result, not the Hash
129
+ results[idx] = query.result
130
+ end
131
+
132
+ results
133
+ rescue Exception
134
+ # TODO rescue at a higher level so it will catch errors in analysis, too
135
+ # Assign values here so that the query's `@executed` becomes true
136
+ queries.map { |q| q.result_values ||= {} }
137
+ raise
138
+ ensure
139
+ queries.map { |query|
140
+ runtime = query.context.namespace(:interpreter_runtime)[:runtime]
141
+ if runtime
142
+ runtime.delete_all_interpreter_context
143
+ end
144
+ }
145
+ end
103
146
  end
104
147
  end
105
- nil
106
148
  end
107
149
 
108
150
  class ListResultFailedError < GraphQL::Error
@@ -1,6 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
  require "graphql/execution/lazy/lazy_method_map"
3
- require "graphql/execution/lazy/resolve"
4
3
 
5
4
  module GraphQL
6
5
  module Execution
@@ -13,23 +12,14 @@ module GraphQL
13
12
  # - It has no error-catching functionality
14
13
  # @api private
15
14
  class Lazy
16
- # Traverse `val`, lazily resolving any values along the way
17
- # @param val [Object] A data structure containing mixed plain values and `Lazy` instances
18
- # @return void
19
- def self.resolve(val)
20
- Resolve.resolve(val)
21
- end
22
-
23
- attr_reader :path, :field
15
+ attr_reader :field
24
16
 
25
17
  # Create a {Lazy} which will get its inner value by calling the block
26
- # @param path [Array<String, Integer>]
27
18
  # @param field [GraphQL::Schema::Field]
28
19
  # @param get_value_func [Proc] a block to get the inner value (later)
29
- def initialize(path: nil, field: nil, &get_value_func)
20
+ def initialize(field: nil, &get_value_func)
30
21
  @get_value_func = get_value_func
31
22
  @resolved = false
32
- @path = path
33
23
  @field = field
34
24
  end
35
25
 
@@ -37,18 +27,18 @@ module GraphQL
37
27
  def value
38
28
  if !@resolved
39
29
  @resolved = true
40
- @value = begin
41
- v = @get_value_func.call
42
- if v.is_a?(Lazy)
43
- v = v.value
44
- end
45
- v
46
- rescue GraphQL::ExecutionError => err
47
- err
30
+ v = @get_value_func.call
31
+ if v.is_a?(Lazy)
32
+ v = v.value
48
33
  end
34
+ @value = v
49
35
  end
50
36
 
51
- if @value.is_a?(StandardError)
37
+ # `SKIP` was made into a subclass of `GraphQL::Error` to improve runtime performance
38
+ # (fewer clauses in a hot `case` block), but now it requires special handling here.
39
+ # I think it's still worth it for the performance win, but if the number of special
40
+ # cases grows, then maybe it's worth rethinking somehow.
41
+ if @value.is_a?(StandardError) && @value != GraphQL::Execution::SKIP
52
42
  raise @value
53
43
  else
54
44
  @value
@@ -55,7 +55,7 @@ module GraphQL
55
55
  @arguments
56
56
  else
57
57
  @arguments = if @field
58
- @query.schema.after_lazy(@query.arguments_for(@ast_nodes.first, @field)) do |args|
58
+ @query.after_lazy(@query.arguments_for(@ast_nodes.first, @field)) do |args|
59
59
  args.is_a?(Execution::Interpreter::Arguments) ? args.keyword_arguments : args
60
60
  end
61
61
  else
@@ -76,8 +76,24 @@ module GraphQL
76
76
  # @param field_name [String, Symbol]
77
77
  # @param arguments [Hash] Arguments which must match in the selection
78
78
  # @return [Boolean]
79
- def selects?(field_name, arguments: nil)
80
- selection(field_name, arguments: arguments).selected?
79
+ def selects?(field_name, selected_type: @selected_type, arguments: nil)
80
+ selection(field_name, selected_type: selected_type, arguments: arguments).selected?
81
+ end
82
+
83
+ # True if this node has a selection with alias matching `alias_name`.
84
+ # If `alias_name` is a String, it is treated as a GraphQL-style (camelized)
85
+ # field name and used verbatim. If `alias_name` is a Symbol, it is
86
+ # treated as a Ruby-style (underscored) name and camelized before comparing.
87
+ #
88
+ # If `arguments:` is provided, each provided key/value will be matched
89
+ # against the arguments in the next selection. This method will return false
90
+ # if any of the given `arguments:` are not present and matching in the next selection.
91
+ # (But, the next selection may contain _more_ than the given arguments.)
92
+ # @param alias_name [String, Symbol]
93
+ # @param arguments [Hash] Arguments which must match in the selection
94
+ # @return [Boolean]
95
+ def selects_alias?(alias_name, arguments: nil)
96
+ alias_selection(alias_name, arguments: arguments).selected?
81
97
  end
82
98
 
83
99
  # @return [Boolean] True if this lookahead represents a field that was requested
@@ -87,27 +103,57 @@ module GraphQL
87
103
 
88
104
  # Like {#selects?}, but can be used for chaining.
89
105
  # It returns a null object (check with {#selected?})
106
+ # @param field_name [String, Symbol]
90
107
  # @return [GraphQL::Execution::Lookahead]
91
108
  def selection(field_name, selected_type: @selected_type, arguments: nil)
92
- next_field_name = normalize_name(field_name)
93
-
94
- next_field_defn = get_class_based_field(selected_type, next_field_name)
95
- if next_field_defn
96
- next_nodes = []
97
- @ast_nodes.each do |ast_node|
98
- ast_node.selections.each do |selection|
99
- find_selected_nodes(selection, next_field_name, next_field_defn, arguments: arguments, matches: next_nodes)
100
- end
109
+ next_field_defn = case field_name
110
+ when String
111
+ @query.get_field(selected_type, field_name)
112
+ when Symbol
113
+ # Try to avoid the `.to_s` below, if possible
114
+ all_fields = if selected_type.kind.fields?
115
+ @query.warden.fields(selected_type)
116
+ else
117
+ # Handle unions by checking possible
118
+ @query.warden
119
+ .possible_types(selected_type)
120
+ .map { |t| @query.warden.fields(t) }
121
+ .tap(&:flatten!)
101
122
  end
102
123
 
103
- if next_nodes.any?
104
- Lookahead.new(query: @query, ast_nodes: next_nodes, field: next_field_defn, owner_type: selected_type)
124
+
125
+ if (match_by_orig_name = all_fields.find { |f| f.original_name == field_name })
126
+ match_by_orig_name
105
127
  else
106
- NULL_LOOKAHEAD
128
+ # Symbol#name is only present on 3.0+
129
+ sym_s = field_name.respond_to?(:name) ? field_name.name : field_name.to_s
130
+ guessed_name = Schema::Member::BuildType.camelize(sym_s)
131
+ @query.get_field(selected_type, guessed_name)
107
132
  end
108
- else
109
- NULL_LOOKAHEAD
110
133
  end
134
+ lookahead_for_selection(next_field_defn, selected_type, arguments)
135
+ end
136
+
137
+ # Like {#selection}, but for aliases.
138
+ # It returns a null object (check with {#selected?})
139
+ # @return [GraphQL::Execution::Lookahead]
140
+ def alias_selection(alias_name, selected_type: @selected_type, arguments: nil)
141
+ alias_cache_key = [alias_name, arguments]
142
+ return alias_selections[key] if alias_selections.key?(alias_name)
143
+
144
+ alias_node = lookup_alias_node(ast_nodes, alias_name)
145
+ return NULL_LOOKAHEAD unless alias_node
146
+
147
+ next_field_defn = @query.get_field(selected_type, alias_node.name)
148
+
149
+ alias_arguments = @query.arguments_for(alias_node, next_field_defn)
150
+ if alias_arguments.is_a?(::GraphQL::Execution::Interpreter::Arguments)
151
+ alias_arguments = alias_arguments.keyword_arguments
152
+ end
153
+
154
+ return NULL_LOOKAHEAD if arguments && arguments != alias_arguments
155
+
156
+ alias_selections[alias_cache_key] = lookahead_for_selection(next_field_defn, selected_type, alias_arguments, alias_name)
111
157
  end
112
158
 
113
159
  # Like {#selection}, but for all nodes.
@@ -137,7 +183,7 @@ module GraphQL
137
183
 
138
184
  subselections_by_type.each do |type, ast_nodes_by_response_key|
139
185
  ast_nodes_by_response_key.each do |response_key, ast_nodes|
140
- field_defn = get_class_based_field(type, ast_nodes.first.name)
186
+ field_defn = @query.get_field(type, ast_nodes.first.name)
141
187
  lookahead = Lookahead.new(query: @query, ast_nodes: ast_nodes, field: field_defn, owner_type: type)
142
188
  subselections.push(lookahead)
143
189
  end
@@ -196,34 +242,10 @@ module GraphQL
196
242
 
197
243
  private
198
244
 
199
- # If it's a symbol, stringify and camelize it
200
- def normalize_name(name)
201
- if name.is_a?(Symbol)
202
- Schema::Member::BuildType.camelize(name.to_s)
203
- else
204
- name
205
- end
206
- end
207
-
208
- def normalize_keyword(keyword)
209
- if keyword.is_a?(String)
210
- Schema::Member::BuildType.underscore(keyword).to_sym
211
- else
212
- keyword
213
- end
214
- end
215
-
216
- # Wrap get_field and ensure that it returns a GraphQL::Schema::Field.
217
- # Remove this when legacy execution is removed.
218
- def get_class_based_field(type, name)
219
- f = @query.get_field(type, name)
220
- f && f.type_class
221
- end
222
-
223
245
  def skipped_by_directive?(ast_selection)
224
246
  ast_selection.directives.each do |directive|
225
247
  dir_defn = @query.schema.directives.fetch(directive.name)
226
- directive_class = dir_defn.type_class
248
+ directive_class = dir_defn
227
249
  if directive_class
228
250
  dir_args = @query.arguments_for(directive, dir_defn)
229
251
  return true unless directive_class.static_include?(dir_args, @query.context)
@@ -244,7 +266,7 @@ module GraphQL
244
266
  elsif arguments.nil? || arguments.empty?
245
267
  selections_on_type[response_key] = [ast_selection]
246
268
  else
247
- field_defn = get_class_based_field(selected_type, ast_selection.name)
269
+ field_defn = @query.get_field(selected_type, ast_selection.name)
248
270
  if arguments_match?(arguments, field_defn, ast_selection)
249
271
  selections_on_type[response_key] = [ast_selection]
250
272
  end
@@ -254,14 +276,14 @@ module GraphQL
254
276
  subselections_on_type = selections_on_type
255
277
  if (t = ast_selection.type)
256
278
  # Assuming this is valid, that `t` will be found.
257
- on_type = @query.schema.get_type(t.name).type_class
279
+ on_type = @query.get_type(t.name)
258
280
  subselections_on_type = subselections_by_type[on_type] ||= {}
259
281
  end
260
282
  find_selections(subselections_by_type, subselections_on_type, on_type, ast_selection.selections, arguments)
261
283
  when GraphQL::Language::Nodes::FragmentSpread
262
- frag_defn = @query.fragments[ast_selection.name] || raise("Invariant: Can't look ahead to nonexistent fragment #{ast_selection.name} (found: #{@query.fragments.keys})")
284
+ frag_defn = lookup_fragment(ast_selection)
263
285
  # Again, assuming a valid AST
264
- on_type = @query.schema.get_type(frag_defn.type.name).type_class
286
+ on_type = @query.get_type(frag_defn.type.name)
265
287
  subselections_on_type = subselections_by_type[on_type] ||= {}
266
288
  find_selections(subselections_by_type, subselections_on_type, on_type, frag_defn.selections, arguments)
267
289
  else
@@ -272,11 +294,11 @@ module GraphQL
272
294
 
273
295
  # If a selection on `node` matches `field_name` (which is backed by `field_defn`)
274
296
  # and matches the `arguments:` constraints, then add that node to `matches`
275
- def find_selected_nodes(node, field_name, field_defn, arguments:, matches:)
297
+ def find_selected_nodes(node, field_name, field_defn, arguments:, matches:, alias_name: NOT_CONFIGURED)
276
298
  return if skipped_by_directive?(node)
277
299
  case node
278
300
  when GraphQL::Language::Nodes::Field
279
- if node.name == field_name
301
+ if node.name == field_name && (NOT_CONFIGURED.equal?(alias_name) || node.alias == alias_name)
280
302
  if arguments.nil? || arguments.empty?
281
303
  # No constraint applied
282
304
  matches << node
@@ -285,10 +307,10 @@ module GraphQL
285
307
  end
286
308
  end
287
309
  when GraphQL::Language::Nodes::InlineFragment
288
- node.selections.each { |s| find_selected_nodes(s, field_name, field_defn, arguments: arguments, matches: matches) }
310
+ node.selections.each { |s| find_selected_nodes(s, field_name, field_defn, arguments: arguments, matches: matches, alias_name: alias_name) }
289
311
  when GraphQL::Language::Nodes::FragmentSpread
290
- frag_defn = @query.fragments[node.name] || raise("Invariant: Can't look ahead to nonexistent fragment #{node.name} (found: #{@query.fragments.keys})")
291
- frag_defn.selections.each { |s| find_selected_nodes(s, field_name, field_defn, arguments: arguments, matches: matches) }
312
+ frag_defn = lookup_fragment(node)
313
+ frag_defn.selections.each { |s| find_selected_nodes(s, field_name, field_defn, arguments: arguments, matches: matches, alias_name: alias_name) }
292
314
  else
293
315
  raise "Unexpected selection comparison on #{node.class.name} (#{node})"
294
316
  end
@@ -297,11 +319,60 @@ module GraphQL
297
319
  def arguments_match?(arguments, field_defn, field_node)
298
320
  query_kwargs = @query.arguments_for(field_node, field_defn)
299
321
  arguments.all? do |arg_name, arg_value|
300
- arg_name = normalize_keyword(arg_name)
322
+ arg_name_sym = if arg_name.is_a?(String)
323
+ Schema::Member::BuildType.underscore(arg_name).to_sym
324
+ else
325
+ arg_name
326
+ end
327
+
301
328
  # Make sure the constraint is present with a matching value
302
- query_kwargs.key?(arg_name) && query_kwargs[arg_name] == arg_value
329
+ query_kwargs.key?(arg_name_sym) && query_kwargs[arg_name_sym] == arg_value
330
+ end
331
+ end
332
+
333
+ def lookahead_for_selection(field_defn, selected_type, arguments, alias_name = NOT_CONFIGURED)
334
+ return NULL_LOOKAHEAD unless field_defn
335
+
336
+ next_nodes = []
337
+ field_name = field_defn.name
338
+ @ast_nodes.each do |ast_node|
339
+ ast_node.selections.each do |selection|
340
+ find_selected_nodes(selection, field_name, field_defn, arguments: arguments, matches: next_nodes, alias_name: alias_name)
341
+ end
342
+ end
343
+
344
+ return NULL_LOOKAHEAD if next_nodes.empty?
345
+
346
+ Lookahead.new(query: @query, ast_nodes: next_nodes, field: field_defn, owner_type: selected_type)
347
+ end
348
+
349
+ def alias_selections
350
+ return @alias_selections if defined?(@alias_selections)
351
+ @alias_selections ||= {}
352
+ end
353
+
354
+ def lookup_alias_node(nodes, name)
355
+ return if nodes.empty?
356
+
357
+ nodes.flat_map(&:children)
358
+ .flat_map { |child| unwrap_fragments(child) }
359
+ .find { |child| child.is_a?(GraphQL::Language::Nodes::Field) && child.alias == name }
360
+ end
361
+
362
+ def unwrap_fragments(node)
363
+ case node
364
+ when GraphQL::Language::Nodes::InlineFragment
365
+ node.children
366
+ when GraphQL::Language::Nodes::FragmentSpread
367
+ lookup_fragment(node).children
368
+ else
369
+ [node]
303
370
  end
304
371
  end
372
+
373
+ def lookup_fragment(ast_selection)
374
+ @query.fragments[ast_selection.name] || raise("Invariant: Can't look ahead to nonexistent fragment #{ast_selection.name} (found: #{@query.fragments.keys})")
375
+ end
305
376
  end
306
377
  end
307
378
  end