graphql 1.9.17 → 2.0.21

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 (416) hide show
  1. checksums.yaml +4 -4
  2. data/lib/generators/graphql/core.rb +21 -10
  3. data/lib/generators/graphql/enum_generator.rb +4 -10
  4. data/lib/generators/graphql/field_extractor.rb +31 -0
  5. data/lib/generators/graphql/input_generator.rb +50 -0
  6. data/lib/generators/graphql/install/mutation_root_generator.rb +34 -0
  7. data/lib/generators/graphql/{templates → install/templates}/base_mutation.erb +2 -0
  8. data/lib/generators/graphql/{templates → install/templates}/mutation_type.erb +2 -0
  9. data/lib/generators/graphql/install_generator.rb +45 -8
  10. data/lib/generators/graphql/interface_generator.rb +7 -7
  11. data/lib/generators/graphql/loader_generator.rb +1 -0
  12. data/lib/generators/graphql/mutation_create_generator.rb +22 -0
  13. data/lib/generators/graphql/mutation_delete_generator.rb +22 -0
  14. data/lib/generators/graphql/mutation_generator.rb +6 -30
  15. data/lib/generators/graphql/mutation_update_generator.rb +22 -0
  16. data/lib/generators/graphql/object_generator.rb +28 -12
  17. data/lib/generators/graphql/orm_mutations_base.rb +40 -0
  18. data/lib/generators/graphql/relay.rb +49 -0
  19. data/lib/generators/graphql/relay_generator.rb +21 -0
  20. data/lib/generators/graphql/scalar_generator.rb +4 -2
  21. data/lib/generators/graphql/templates/base_argument.erb +2 -0
  22. data/lib/generators/graphql/templates/base_connection.erb +8 -0
  23. data/lib/generators/graphql/templates/base_edge.erb +8 -0
  24. data/lib/generators/graphql/templates/base_enum.erb +2 -0
  25. data/lib/generators/graphql/templates/base_field.erb +2 -0
  26. data/lib/generators/graphql/templates/base_input_object.erb +2 -0
  27. data/lib/generators/graphql/templates/base_interface.erb +2 -0
  28. data/lib/generators/graphql/templates/base_object.erb +2 -0
  29. data/lib/generators/graphql/templates/base_scalar.erb +2 -0
  30. data/lib/generators/graphql/templates/base_union.erb +2 -0
  31. data/lib/generators/graphql/templates/enum.erb +7 -1
  32. data/lib/generators/graphql/templates/graphql_controller.erb +16 -12
  33. data/lib/generators/graphql/templates/input.erb +9 -0
  34. data/lib/generators/graphql/templates/interface.erb +6 -2
  35. data/lib/generators/graphql/templates/loader.erb +2 -0
  36. data/lib/generators/graphql/templates/mutation.erb +3 -1
  37. data/lib/generators/graphql/templates/mutation_create.erb +20 -0
  38. data/lib/generators/graphql/templates/mutation_delete.erb +20 -0
  39. data/lib/generators/graphql/templates/mutation_update.erb +21 -0
  40. data/lib/generators/graphql/templates/node_type.erb +9 -0
  41. data/lib/generators/graphql/templates/object.erb +7 -3
  42. data/lib/generators/graphql/templates/query_type.erb +3 -3
  43. data/lib/generators/graphql/templates/scalar.erb +5 -1
  44. data/lib/generators/graphql/templates/schema.erb +25 -27
  45. data/lib/generators/graphql/templates/union.erb +6 -2
  46. data/lib/generators/graphql/type_generator.rb +47 -10
  47. data/lib/generators/graphql/union_generator.rb +5 -5
  48. data/lib/graphql/analysis/ast/field_usage.rb +31 -2
  49. data/lib/graphql/analysis/ast/max_query_complexity.rb +0 -1
  50. data/lib/graphql/analysis/ast/query_complexity.rb +175 -68
  51. data/lib/graphql/analysis/ast/query_depth.rb +0 -1
  52. data/lib/graphql/analysis/ast/visitor.rb +54 -38
  53. data/lib/graphql/analysis/ast.rb +16 -16
  54. data/lib/graphql/analysis.rb +0 -7
  55. data/lib/graphql/backtrace/inspect_result.rb +0 -1
  56. data/lib/graphql/backtrace/table.rb +37 -16
  57. data/lib/graphql/backtrace/trace.rb +96 -0
  58. data/lib/graphql/backtrace/traced_error.rb +0 -1
  59. data/lib/graphql/backtrace/tracer.rb +39 -9
  60. data/lib/graphql/backtrace.rb +26 -18
  61. data/lib/graphql/dataloader/null_dataloader.rb +24 -0
  62. data/lib/graphql/dataloader/request.rb +19 -0
  63. data/lib/graphql/dataloader/request_all.rb +19 -0
  64. data/lib/graphql/dataloader/source.rb +164 -0
  65. data/lib/graphql/dataloader.rb +311 -0
  66. data/lib/graphql/date_encoding_error.rb +16 -0
  67. data/lib/graphql/deprecation.rb +9 -0
  68. data/lib/graphql/dig.rb +1 -1
  69. data/lib/graphql/execution/directive_checks.rb +2 -2
  70. data/lib/graphql/execution/errors.rb +77 -45
  71. data/lib/graphql/execution/interpreter/argument_value.rb +28 -0
  72. data/lib/graphql/execution/interpreter/arguments.rb +88 -0
  73. data/lib/graphql/execution/interpreter/arguments_cache.rb +104 -0
  74. data/lib/graphql/execution/interpreter/handles_raw_value.rb +18 -0
  75. data/lib/graphql/execution/interpreter/resolve.rb +62 -24
  76. data/lib/graphql/execution/interpreter/runtime.rb +830 -417
  77. data/lib/graphql/execution/interpreter.rb +206 -74
  78. data/lib/graphql/execution/lazy/lazy_method_map.rb +4 -0
  79. data/lib/graphql/execution/lazy.rb +11 -21
  80. data/lib/graphql/execution/lookahead.rb +65 -136
  81. data/lib/graphql/execution/multiplex.rb +6 -152
  82. data/lib/graphql/execution.rb +11 -4
  83. data/lib/graphql/filter.rb +8 -3
  84. data/lib/graphql/integer_decoding_error.rb +17 -0
  85. data/lib/graphql/integer_encoding_error.rb +18 -2
  86. data/lib/graphql/introspection/base_object.rb +2 -5
  87. data/lib/graphql/introspection/directive_location_enum.rb +2 -2
  88. data/lib/graphql/introspection/directive_type.rb +12 -6
  89. data/lib/graphql/introspection/dynamic_fields.rb +3 -8
  90. data/lib/graphql/introspection/entry_points.rb +5 -18
  91. data/lib/graphql/introspection/enum_value_type.rb +2 -2
  92. data/lib/graphql/introspection/field_type.rb +9 -5
  93. data/lib/graphql/introspection/input_value_type.rb +41 -11
  94. data/lib/graphql/introspection/introspection_query.rb +6 -92
  95. data/lib/graphql/introspection/schema_type.rb +12 -12
  96. data/lib/graphql/introspection/type_type.rb +34 -17
  97. data/lib/graphql/introspection.rb +100 -0
  98. data/lib/graphql/invalid_null_error.rb +18 -0
  99. data/lib/graphql/language/block_string.rb +20 -5
  100. data/lib/graphql/language/cache.rb +37 -0
  101. data/lib/graphql/language/definition_slice.rb +21 -10
  102. data/lib/graphql/language/document_from_schema_definition.rb +136 -78
  103. data/lib/graphql/language/lexer.rb +216 -1462
  104. data/lib/graphql/language/nodes.rb +129 -132
  105. data/lib/graphql/language/parser.rb +994 -932
  106. data/lib/graphql/language/parser.y +152 -120
  107. data/lib/graphql/language/printer.rb +48 -23
  108. data/lib/graphql/language/sanitized_printer.rb +222 -0
  109. data/lib/graphql/language/token.rb +0 -4
  110. data/lib/graphql/language/visitor.rb +192 -84
  111. data/lib/graphql/language.rb +3 -1
  112. data/lib/graphql/name_validator.rb +2 -7
  113. data/lib/graphql/pagination/active_record_relation_connection.rb +77 -0
  114. data/lib/graphql/pagination/array_connection.rb +79 -0
  115. data/lib/graphql/pagination/connection.rb +253 -0
  116. data/lib/graphql/pagination/connections.rb +135 -0
  117. data/lib/graphql/pagination/mongoid_relation_connection.rb +25 -0
  118. data/lib/graphql/pagination/relation_connection.rb +228 -0
  119. data/lib/graphql/pagination/sequel_dataset_connection.rb +28 -0
  120. data/lib/graphql/pagination.rb +6 -0
  121. data/lib/graphql/parse_error.rb +0 -1
  122. data/lib/graphql/query/context.rb +205 -203
  123. data/lib/graphql/query/fingerprint.rb +26 -0
  124. data/lib/graphql/query/input_validation_result.rb +33 -7
  125. data/lib/graphql/query/null_context.rb +22 -9
  126. data/lib/graphql/query/validation_pipeline.rb +16 -38
  127. data/lib/graphql/query/variable_validation_error.rb +3 -3
  128. data/lib/graphql/query/variables.rb +39 -12
  129. data/lib/graphql/query.rb +95 -43
  130. data/lib/graphql/railtie.rb +6 -102
  131. data/lib/graphql/rake_task/validate.rb +4 -1
  132. data/lib/graphql/rake_task.rb +41 -10
  133. data/lib/graphql/relay/range_add.rb +17 -10
  134. data/lib/graphql/relay.rb +0 -15
  135. data/lib/graphql/rubocop/graphql/base_cop.rb +36 -0
  136. data/lib/graphql/rubocop/graphql/default_null_true.rb +43 -0
  137. data/lib/graphql/rubocop/graphql/default_required_true.rb +43 -0
  138. data/lib/graphql/rubocop.rb +4 -0
  139. data/lib/graphql/schema/addition.rb +245 -0
  140. data/lib/graphql/schema/argument.rb +285 -36
  141. data/lib/graphql/schema/base_64_encoder.rb +2 -0
  142. data/lib/graphql/schema/build_from_definition/resolve_map/default_resolve.rb +1 -1
  143. data/lib/graphql/schema/build_from_definition/resolve_map.rb +13 -5
  144. data/lib/graphql/schema/build_from_definition.rb +348 -205
  145. data/lib/graphql/schema/built_in_types.rb +5 -5
  146. data/lib/graphql/schema/directive/deprecated.rb +18 -0
  147. data/lib/graphql/schema/directive/feature.rb +1 -1
  148. data/lib/graphql/schema/directive/flagged.rb +57 -0
  149. data/lib/graphql/schema/directive/include.rb +2 -2
  150. data/lib/graphql/schema/directive/one_of.rb +12 -0
  151. data/lib/graphql/schema/directive/skip.rb +2 -2
  152. data/lib/graphql/schema/directive/transform.rb +14 -2
  153. data/lib/graphql/schema/directive.rb +134 -15
  154. data/lib/graphql/schema/enum.rb +137 -39
  155. data/lib/graphql/schema/enum_value.rb +17 -23
  156. data/lib/graphql/schema/field/connection_extension.rb +50 -20
  157. data/lib/graphql/schema/field/scope_extension.rb +1 -1
  158. data/lib/graphql/schema/field.rb +504 -331
  159. data/lib/graphql/schema/field_extension.rb +86 -2
  160. data/lib/graphql/schema/find_inherited_value.rb +12 -1
  161. data/lib/graphql/schema/finder.rb +16 -14
  162. data/lib/graphql/schema/input_object.rb +182 -60
  163. data/lib/graphql/schema/interface.rb +24 -49
  164. data/lib/graphql/schema/introspection_system.rb +103 -37
  165. data/lib/graphql/schema/late_bound_type.rb +9 -2
  166. data/lib/graphql/schema/list.rb +61 -3
  167. data/lib/graphql/schema/loader.rb +144 -96
  168. data/lib/graphql/schema/member/base_dsl_methods.rb +41 -37
  169. data/lib/graphql/schema/member/build_type.rb +24 -15
  170. data/lib/graphql/schema/member/has_arguments.rb +310 -26
  171. data/lib/graphql/schema/member/has_ast_node.rb +32 -0
  172. data/lib/graphql/schema/member/has_deprecation_reason.rb +24 -0
  173. data/lib/graphql/schema/member/has_directives.rb +118 -0
  174. data/lib/graphql/schema/member/has_fields.rb +166 -44
  175. data/lib/graphql/schema/member/has_interfaces.rb +129 -0
  176. data/lib/graphql/schema/member/has_unresolved_type_error.rb +15 -0
  177. data/lib/graphql/schema/member/has_validators.rb +57 -0
  178. data/lib/graphql/schema/member/relay_shortcuts.rb +47 -2
  179. data/lib/graphql/schema/member/type_system_helpers.rb +20 -3
  180. data/lib/graphql/schema/member/validates_input.rb +33 -0
  181. data/lib/graphql/schema/member.rb +11 -6
  182. data/lib/graphql/schema/mutation.rb +4 -9
  183. data/lib/graphql/schema/non_null.rb +34 -4
  184. data/lib/graphql/schema/object.rb +36 -60
  185. data/lib/graphql/schema/printer.rb +16 -35
  186. data/lib/graphql/schema/relay_classic_mutation.rb +91 -44
  187. data/lib/graphql/schema/resolver/has_payload_type.rb +51 -11
  188. data/lib/graphql/schema/resolver.rb +147 -94
  189. data/lib/graphql/schema/scalar.rb +40 -15
  190. data/lib/graphql/schema/subscription.rb +60 -31
  191. data/lib/graphql/schema/timeout.rb +45 -35
  192. data/lib/graphql/schema/type_expression.rb +21 -13
  193. data/lib/graphql/schema/type_membership.rb +23 -6
  194. data/lib/graphql/schema/union.rb +49 -15
  195. data/lib/graphql/schema/unique_within_type.rb +1 -2
  196. data/lib/graphql/schema/validator/allow_blank_validator.rb +29 -0
  197. data/lib/graphql/schema/validator/allow_null_validator.rb +26 -0
  198. data/lib/graphql/schema/validator/exclusion_validator.rb +33 -0
  199. data/lib/graphql/schema/validator/format_validator.rb +48 -0
  200. data/lib/graphql/schema/validator/inclusion_validator.rb +35 -0
  201. data/lib/graphql/schema/validator/length_validator.rb +59 -0
  202. data/lib/graphql/schema/validator/numericality_validator.rb +82 -0
  203. data/lib/graphql/schema/validator/required_validator.rb +82 -0
  204. data/lib/graphql/schema/validator.rb +171 -0
  205. data/lib/graphql/schema/warden.rb +213 -35
  206. data/lib/graphql/schema/wrapper.rb +0 -5
  207. data/lib/graphql/schema.rb +857 -884
  208. data/lib/graphql/static_validation/all_rules.rb +3 -0
  209. data/lib/graphql/static_validation/base_visitor.rb +21 -31
  210. data/lib/graphql/static_validation/definition_dependencies.rb +7 -2
  211. data/lib/graphql/static_validation/error.rb +3 -1
  212. data/lib/graphql/static_validation/literal_validator.rb +69 -26
  213. data/lib/graphql/static_validation/rules/argument_literals_are_compatible.rb +45 -83
  214. data/lib/graphql/static_validation/rules/argument_literals_are_compatible_error.rb +22 -6
  215. data/lib/graphql/static_validation/rules/arguments_are_defined.rb +35 -26
  216. data/lib/graphql/static_validation/rules/arguments_are_defined_error.rb +4 -2
  217. data/lib/graphql/static_validation/rules/directives_are_defined.rb +12 -6
  218. data/lib/graphql/static_validation/rules/directives_are_in_valid_locations.rb +14 -14
  219. data/lib/graphql/static_validation/rules/fields_are_defined_on_type.rb +4 -4
  220. data/lib/graphql/static_validation/rules/fields_have_appropriate_selections.rb +15 -7
  221. data/lib/graphql/static_validation/rules/fields_will_merge.rb +96 -53
  222. data/lib/graphql/static_validation/rules/fields_will_merge_error.rb +25 -4
  223. data/lib/graphql/static_validation/rules/fragment_spreads_are_possible.rb +3 -3
  224. data/lib/graphql/static_validation/rules/fragments_are_finite.rb +2 -2
  225. data/lib/graphql/static_validation/rules/input_object_names_are_unique.rb +30 -0
  226. data/lib/graphql/static_validation/rules/input_object_names_are_unique_error.rb +30 -0
  227. data/lib/graphql/static_validation/rules/one_of_input_objects_are_valid.rb +66 -0
  228. data/lib/graphql/static_validation/rules/one_of_input_objects_are_valid_error.rb +29 -0
  229. data/lib/graphql/static_validation/rules/query_root_exists.rb +17 -0
  230. data/lib/graphql/static_validation/rules/query_root_exists_error.rb +26 -0
  231. data/lib/graphql/static_validation/rules/required_arguments_are_present.rb +4 -2
  232. data/lib/graphql/static_validation/rules/required_input_object_attributes_are_present.rb +9 -10
  233. data/lib/graphql/static_validation/rules/unique_directives_per_location.rb +13 -7
  234. data/lib/graphql/static_validation/rules/variable_default_values_are_correctly_typed.rb +12 -13
  235. data/lib/graphql/static_validation/rules/variable_usages_are_allowed.rb +19 -14
  236. data/lib/graphql/static_validation/rules/variables_are_input_types.rb +1 -1
  237. data/lib/graphql/static_validation/rules/variables_are_used_and_defined.rb +5 -3
  238. data/lib/graphql/static_validation/type_stack.rb +2 -2
  239. data/lib/graphql/static_validation/validation_context.rb +13 -3
  240. data/lib/graphql/static_validation/validation_timeout_error.rb +25 -0
  241. data/lib/graphql/static_validation/validator.rb +32 -20
  242. data/lib/graphql/static_validation.rb +1 -2
  243. data/lib/graphql/string_encoding_error.rb +13 -3
  244. data/lib/graphql/subscriptions/action_cable_subscriptions.rb +129 -22
  245. data/lib/graphql/subscriptions/broadcast_analyzer.rb +81 -0
  246. data/lib/graphql/subscriptions/default_subscription_resolve_extension.rb +58 -0
  247. data/lib/graphql/subscriptions/event.rb +84 -35
  248. data/lib/graphql/subscriptions/instrumentation.rb +0 -47
  249. data/lib/graphql/subscriptions/serialize.rb +53 -6
  250. data/lib/graphql/subscriptions.rb +137 -57
  251. data/lib/graphql/tracing/active_support_notifications_trace.rb +16 -0
  252. data/lib/graphql/tracing/active_support_notifications_tracing.rb +8 -17
  253. data/lib/graphql/tracing/appoptics_trace.rb +231 -0
  254. data/lib/graphql/tracing/appoptics_tracing.rb +173 -0
  255. data/lib/graphql/tracing/appsignal_trace.rb +77 -0
  256. data/lib/graphql/tracing/appsignal_tracing.rb +23 -0
  257. data/lib/graphql/tracing/data_dog_trace.rb +148 -0
  258. data/lib/graphql/tracing/data_dog_tracing.rb +34 -2
  259. data/lib/graphql/tracing/legacy_trace.rb +65 -0
  260. data/lib/graphql/tracing/new_relic_trace.rb +75 -0
  261. data/lib/graphql/tracing/new_relic_tracing.rb +9 -12
  262. data/lib/graphql/tracing/notifications_trace.rb +42 -0
  263. data/lib/graphql/tracing/notifications_tracing.rb +59 -0
  264. data/lib/graphql/tracing/platform_trace.rb +109 -0
  265. data/lib/graphql/tracing/platform_tracing.rb +76 -35
  266. data/lib/graphql/tracing/prometheus_trace.rb +89 -0
  267. data/lib/graphql/tracing/prometheus_tracing/graphql_collector.rb +5 -2
  268. data/lib/graphql/tracing/prometheus_tracing.rb +11 -3
  269. data/lib/graphql/tracing/scout_trace.rb +72 -0
  270. data/lib/graphql/tracing/scout_tracing.rb +19 -0
  271. data/lib/graphql/tracing/statsd_trace.rb +56 -0
  272. data/lib/graphql/tracing/statsd_tracing.rb +42 -0
  273. data/lib/graphql/tracing/trace.rb +75 -0
  274. data/lib/graphql/tracing.rb +23 -67
  275. data/lib/graphql/type_kinds.rb +6 -3
  276. data/lib/graphql/types/big_int.rb +5 -1
  277. data/lib/graphql/types/int.rb +10 -3
  278. data/lib/graphql/types/iso_8601_date.rb +20 -9
  279. data/lib/graphql/types/iso_8601_date_time.rb +36 -10
  280. data/lib/graphql/types/relay/base_connection.rb +18 -90
  281. data/lib/graphql/types/relay/base_edge.rb +2 -34
  282. data/lib/graphql/types/relay/connection_behaviors.rb +176 -0
  283. data/lib/graphql/types/relay/edge_behaviors.rb +75 -0
  284. data/lib/graphql/types/relay/has_node_field.rb +41 -0
  285. data/lib/graphql/types/relay/has_nodes_field.rb +41 -0
  286. data/lib/graphql/types/relay/node.rb +2 -4
  287. data/lib/graphql/types/relay/node_behaviors.rb +25 -0
  288. data/lib/graphql/types/relay/page_info.rb +2 -14
  289. data/lib/graphql/types/relay/page_info_behaviors.rb +30 -0
  290. data/lib/graphql/types/relay.rb +10 -5
  291. data/lib/graphql/types/string.rb +8 -2
  292. data/lib/graphql/unauthorized_error.rb +2 -2
  293. data/lib/graphql/unresolved_type_error.rb +2 -2
  294. data/lib/graphql/version.rb +1 -1
  295. data/lib/graphql.rb +63 -65
  296. data/readme.md +3 -6
  297. metadata +127 -236
  298. data/lib/graphql/analysis/analyze_query.rb +0 -91
  299. data/lib/graphql/analysis/field_usage.rb +0 -45
  300. data/lib/graphql/analysis/max_query_complexity.rb +0 -26
  301. data/lib/graphql/analysis/max_query_depth.rb +0 -26
  302. data/lib/graphql/analysis/query_complexity.rb +0 -88
  303. data/lib/graphql/analysis/query_depth.rb +0 -43
  304. data/lib/graphql/analysis/reducer_state.rb +0 -48
  305. data/lib/graphql/argument.rb +0 -159
  306. data/lib/graphql/authorization.rb +0 -82
  307. data/lib/graphql/backwards_compatibility.rb +0 -60
  308. data/lib/graphql/base_type.rb +0 -226
  309. data/lib/graphql/boolean_type.rb +0 -2
  310. data/lib/graphql/compatibility/execution_specification/counter_schema.rb +0 -53
  311. data/lib/graphql/compatibility/execution_specification/specification_schema.rb +0 -200
  312. data/lib/graphql/compatibility/execution_specification.rb +0 -435
  313. data/lib/graphql/compatibility/lazy_execution_specification/lazy_schema.rb +0 -111
  314. data/lib/graphql/compatibility/lazy_execution_specification.rb +0 -213
  315. data/lib/graphql/compatibility/query_parser_specification/parse_error_specification.rb +0 -91
  316. data/lib/graphql/compatibility/query_parser_specification/query_assertions.rb +0 -79
  317. data/lib/graphql/compatibility/query_parser_specification.rb +0 -264
  318. data/lib/graphql/compatibility/schema_parser_specification.rb +0 -680
  319. data/lib/graphql/compatibility.rb +0 -5
  320. data/lib/graphql/define/assign_argument.rb +0 -12
  321. data/lib/graphql/define/assign_connection.rb +0 -13
  322. data/lib/graphql/define/assign_enum_value.rb +0 -18
  323. data/lib/graphql/define/assign_global_id_field.rb +0 -11
  324. data/lib/graphql/define/assign_mutation_function.rb +0 -34
  325. data/lib/graphql/define/assign_object_field.rb +0 -42
  326. data/lib/graphql/define/defined_object_proxy.rb +0 -50
  327. data/lib/graphql/define/instance_definable.rb +0 -300
  328. data/lib/graphql/define/no_definition_error.rb +0 -7
  329. data/lib/graphql/define/non_null_with_bang.rb +0 -16
  330. data/lib/graphql/define/type_definer.rb +0 -31
  331. data/lib/graphql/define.rb +0 -31
  332. data/lib/graphql/deprecated_dsl.rb +0 -42
  333. data/lib/graphql/directive/deprecated_directive.rb +0 -13
  334. data/lib/graphql/directive/include_directive.rb +0 -2
  335. data/lib/graphql/directive/skip_directive.rb +0 -2
  336. data/lib/graphql/directive.rb +0 -104
  337. data/lib/graphql/enum_type.rb +0 -193
  338. data/lib/graphql/execution/execute.rb +0 -326
  339. data/lib/graphql/execution/flatten.rb +0 -40
  340. data/lib/graphql/execution/instrumentation.rb +0 -92
  341. data/lib/graphql/execution/interpreter/hash_response.rb +0 -46
  342. data/lib/graphql/execution/lazy/resolve.rb +0 -91
  343. data/lib/graphql/execution/typecast.rb +0 -50
  344. data/lib/graphql/field/resolve.rb +0 -59
  345. data/lib/graphql/field.rb +0 -330
  346. data/lib/graphql/float_type.rb +0 -2
  347. data/lib/graphql/function.rb +0 -153
  348. data/lib/graphql/id_type.rb +0 -2
  349. data/lib/graphql/input_object_type.rb +0 -154
  350. data/lib/graphql/int_type.rb +0 -2
  351. data/lib/graphql/interface_type.rb +0 -86
  352. data/lib/graphql/internal_representation/document.rb +0 -27
  353. data/lib/graphql/internal_representation/node.rb +0 -206
  354. data/lib/graphql/internal_representation/print.rb +0 -51
  355. data/lib/graphql/internal_representation/rewrite.rb +0 -184
  356. data/lib/graphql/internal_representation/scope.rb +0 -88
  357. data/lib/graphql/internal_representation/visit.rb +0 -36
  358. data/lib/graphql/internal_representation.rb +0 -7
  359. data/lib/graphql/language/lexer.rl +0 -258
  360. data/lib/graphql/list_type.rb +0 -80
  361. data/lib/graphql/literal_validation_error.rb +0 -6
  362. data/lib/graphql/non_null_type.rb +0 -81
  363. data/lib/graphql/object_type.rb +0 -141
  364. data/lib/graphql/query/arguments.rb +0 -187
  365. data/lib/graphql/query/arguments_cache.rb +0 -25
  366. data/lib/graphql/query/executor.rb +0 -53
  367. data/lib/graphql/query/literal_input.rb +0 -116
  368. data/lib/graphql/query/serial_execution/field_resolution.rb +0 -92
  369. data/lib/graphql/query/serial_execution/operation_resolution.rb +0 -19
  370. data/lib/graphql/query/serial_execution/selection_resolution.rb +0 -23
  371. data/lib/graphql/query/serial_execution/value_resolution.rb +0 -87
  372. data/lib/graphql/query/serial_execution.rb +0 -39
  373. data/lib/graphql/relay/array_connection.rb +0 -85
  374. data/lib/graphql/relay/base_connection.rb +0 -172
  375. data/lib/graphql/relay/connection_instrumentation.rb +0 -54
  376. data/lib/graphql/relay/connection_resolve.rb +0 -43
  377. data/lib/graphql/relay/connection_type.rb +0 -40
  378. data/lib/graphql/relay/edge.rb +0 -27
  379. data/lib/graphql/relay/edge_type.rb +0 -18
  380. data/lib/graphql/relay/edges_instrumentation.rb +0 -40
  381. data/lib/graphql/relay/global_id_resolve.rb +0 -18
  382. data/lib/graphql/relay/mongo_relation_connection.rb +0 -50
  383. data/lib/graphql/relay/mutation/instrumentation.rb +0 -23
  384. data/lib/graphql/relay/mutation/resolve.rb +0 -56
  385. data/lib/graphql/relay/mutation/result.rb +0 -38
  386. data/lib/graphql/relay/mutation.rb +0 -190
  387. data/lib/graphql/relay/node.rb +0 -36
  388. data/lib/graphql/relay/page_info.rb +0 -7
  389. data/lib/graphql/relay/relation_connection.rb +0 -190
  390. data/lib/graphql/relay/type_extensions.rb +0 -30
  391. data/lib/graphql/scalar_type.rb +0 -133
  392. data/lib/graphql/schema/catchall_middleware.rb +0 -35
  393. data/lib/graphql/schema/default_parse_error.rb +0 -10
  394. data/lib/graphql/schema/default_type_error.rb +0 -15
  395. data/lib/graphql/schema/member/accepts_definition.rb +0 -152
  396. data/lib/graphql/schema/member/cached_graphql_definition.rb +0 -26
  397. data/lib/graphql/schema/member/instrumentation.rb +0 -132
  398. data/lib/graphql/schema/middleware_chain.rb +0 -82
  399. data/lib/graphql/schema/possible_types.rb +0 -39
  400. data/lib/graphql/schema/rescue_middleware.rb +0 -60
  401. data/lib/graphql/schema/timeout_middleware.rb +0 -86
  402. data/lib/graphql/schema/traversal.rb +0 -228
  403. data/lib/graphql/schema/validation.rb +0 -303
  404. data/lib/graphql/static_validation/default_visitor.rb +0 -15
  405. data/lib/graphql/static_validation/no_validate_visitor.rb +0 -10
  406. data/lib/graphql/string_type.rb +0 -2
  407. data/lib/graphql/subscriptions/subscription_root.rb +0 -66
  408. data/lib/graphql/tracing/skylight_tracing.rb +0 -62
  409. data/lib/graphql/types/relay/base_field.rb +0 -22
  410. data/lib/graphql/types/relay/base_interface.rb +0 -29
  411. data/lib/graphql/types/relay/base_object.rb +0 -26
  412. data/lib/graphql/types/relay/node_field.rb +0 -43
  413. data/lib/graphql/types/relay/nodes_field.rb +0 -45
  414. data/lib/graphql/union_type.rb +0 -128
  415. data/lib/graphql/upgrader/member.rb +0 -936
  416. data/lib/graphql/upgrader/schema.rb +0 -37
@@ -1,97 +1,229 @@
1
1
  # frozen_string_literal: true
2
+ require "fiber"
3
+ require "graphql/execution/interpreter/argument_value"
4
+ require "graphql/execution/interpreter/arguments"
5
+ require "graphql/execution/interpreter/arguments_cache"
2
6
  require "graphql/execution/interpreter/execution_errors"
3
- require "graphql/execution/interpreter/hash_response"
4
7
  require "graphql/execution/interpreter/runtime"
5
8
  require "graphql/execution/interpreter/resolve"
9
+ require "graphql/execution/interpreter/handles_raw_value"
6
10
 
7
11
  module GraphQL
8
12
  module Execution
9
13
  class Interpreter
10
- def initialize
11
- 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
12
18
 
13
- # Support `Executor` :S
14
- def execute(_operation, _root_type, query)
15
- runtime = evaluate(query)
16
- sync_lazies(query: query)
17
- runtime.final_value
18
- 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
+ GraphQL::Query.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
19
35
 
20
- def self.use(schema_defn)
21
- schema_defn.target.interpreter = true
22
- # Reach through the legacy objects for the actual class defn
23
- schema_class = schema_defn.target.class
24
- # This is not good, since both of these are holding state now,
25
- # we have to update both :(
26
- [schema_class, schema_defn].each do |schema_config|
27
- schema_config.query_execution_strategy(GraphQL::Execution::Interpreter)
28
- schema_config.mutation_execution_strategy(GraphQL::Execution::Interpreter)
29
- schema_config.subscription_execution_strategy(GraphQL::Execution::Interpreter)
30
- end
31
- 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
+ query_instrumenters = schema.instrumenters[:query]
41
+ multiplex_instrumenters = schema.instrumenters[:multiplex]
42
+ lazies_at_depth = Hash.new { |h, k| h[k] = [] }
32
43
 
33
- def self.begin_multiplex(multiplex)
34
- # Since this is basically the batching context,
35
- # share it for a whole multiplex
36
- multiplex.context[:interpreter_instance] ||= self.new
37
- end
44
+ # First, run multiplex instrumentation, then query instrumentation for each query
45
+ call_hooks(multiplex_instrumenters, multiplex, :before_multiplex, :after_multiplex) do
46
+ each_query_call_hooks(query_instrumenters, queries) do
47
+ schema = multiplex.schema
48
+ multiplex_analyzers = schema.multiplex_analyzers
49
+ queries = multiplex.queries
50
+ if multiplex.max_complexity
51
+ multiplex_analyzers += [GraphQL::Analysis::AST::MaxQueryComplexity]
52
+ end
38
53
 
39
- def self.begin_query(query, multiplex)
40
- # The batching context is shared by the multiplex,
41
- # so fetch it out and use that instance.
42
- interpreter =
43
- query.context.namespace(:interpreter)[:interpreter_instance] =
44
- multiplex.context[:interpreter_instance]
45
- interpreter.evaluate(query)
46
- query
47
- end
54
+ schema.analysis_engine.analyze_multiplex(multiplex, multiplex_analyzers)
55
+ begin
56
+ # Since this is basically the batching context,
57
+ # share it for a whole multiplex
58
+ multiplex.context[:interpreter_instance] ||= multiplex.schema.query_execution_strategy.new
59
+ # Do as much eager evaluation of the query as possible
60
+ results = []
61
+ queries.each_with_index do |query, idx|
62
+ multiplex.dataloader.append_job {
63
+ operation = query.selected_operation
64
+ result = if operation.nil? || !query.valid? || query.context.errors.any?
65
+ NO_OPERATION
66
+ else
67
+ begin
68
+ # Although queries in a multiplex _share_ an Interpreter instance,
69
+ # they also have another item of state, which is private to that query
70
+ # in particular, assign it here:
71
+ runtime = Runtime.new(query: query, lazies_at_depth: lazies_at_depth)
72
+ query.context.namespace(:interpreter_runtime)[:runtime] = runtime
48
73
 
49
- def self.finish_multiplex(_results, multiplex)
50
- interpreter = multiplex.context[:interpreter_instance]
51
- interpreter.sync_lazies(multiplex: multiplex)
52
- end
74
+ query.current_trace.execute_query(query: query) do
75
+ runtime.run_eager
76
+ end
77
+ rescue GraphQL::ExecutionError => err
78
+ query.context.errors << err
79
+ NO_OPERATION
80
+ end
81
+ end
82
+ results[idx] = result
83
+ }
84
+ end
53
85
 
54
- def self.finish_query(query, _multiplex)
55
- {
56
- "data" => query.context.namespace(:interpreter)[:runtime].final_value
57
- }
58
- end
86
+ multiplex.dataloader.run
87
+
88
+ # Then, work through lazy results in a breadth-first way
89
+ multiplex.dataloader.append_job {
90
+ tracer = multiplex
91
+ query = multiplex.queries.length == 1 ? multiplex.queries[0] : nil
92
+ queries = multiplex ? multiplex.queries : [query]
93
+ final_values = queries.map do |query|
94
+ runtime = query.context.namespace(:interpreter_runtime)[:runtime]
95
+ # it might not be present if the query has an error
96
+ runtime ? runtime.final_result : nil
97
+ end
98
+ final_values.compact!
99
+ tracer.current_trace.execute_query_lazy(multiplex: multiplex, query: query) do
100
+ Interpreter::Resolve.resolve_each_depth(lazies_at_depth, multiplex.dataloader)
101
+ end
102
+ queries.each do |query|
103
+ runtime = query.context.namespace(:interpreter_runtime)[:runtime]
104
+ if runtime
105
+ runtime.delete_all_interpreter_context
106
+ end
107
+ end
108
+ }
109
+ multiplex.dataloader.run
110
+
111
+ # Then, find all errors and assign the result to the query object
112
+ results.each_with_index do |data_result, idx|
113
+ query = queries[idx]
114
+ # Assign the result so that it can be accessed in instrumentation
115
+ query.result_values = if data_result.equal?(NO_OPERATION)
116
+ if !query.valid? || query.context.errors.any?
117
+ # A bit weird, but `Query#static_errors` _includes_ `query.context.errors`
118
+ { "errors" => query.static_errors.map(&:to_h) }
119
+ else
120
+ data_result
121
+ end
122
+ else
123
+ result = {
124
+ "data" => query.context.namespace(:interpreter_runtime)[:runtime].final_result
125
+ }
126
+
127
+ if query.context.errors.any?
128
+ error_result = query.context.errors.map(&:to_h)
129
+ result["errors"] = error_result
130
+ end
59
131
 
60
- # Run the eager part of `query`
61
- # @return {Interpreter::Runtime}
62
- def evaluate(query)
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(
67
- query: query,
68
- response: HashResponse.new,
69
- )
70
- query.context.namespace(:interpreter)[:runtime] = runtime
71
-
72
- query.trace("execute_query", {query: query}) do
73
- runtime.run_eager
132
+ result
133
+ end
134
+ if query.context.namespace?(:__query_result_extensions__)
135
+ query.result_values["extensions"] = query.context.namespace(:__query_result_extensions__)
136
+ end
137
+ # Get the Query::Result, not the Hash
138
+ results[idx] = query.result
139
+ end
140
+
141
+ results
142
+ rescue Exception
143
+ # TODO rescue at a higher level so it will catch errors in analysis, too
144
+ # Assign values here so that the query's `@executed` becomes true
145
+ queries.map { |q| q.result_values ||= {} }
146
+ raise
147
+ ensure
148
+ queries.map { |query|
149
+ runtime = query.context.namespace(:interpreter_runtime)[:runtime]
150
+ if runtime
151
+ runtime.delete_all_interpreter_context
152
+ end
153
+ }
154
+ end
155
+ end
156
+ end
157
+ end
74
158
  end
75
159
 
76
- runtime
77
- end
160
+ private
78
161
 
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]
162
+ # Call the before_ hooks of each query,
163
+ # Then yield if no errors.
164
+ # `call_hooks` takes care of appropriate cleanup.
165
+ def each_query_call_hooks(instrumenters, queries, i = 0)
166
+ if i >= queries.length
167
+ yield
168
+ else
169
+ query = queries[i]
170
+ call_hooks(instrumenters, query, :before_query, :after_query) {
171
+ each_query_call_hooks(instrumenters, queries, i + 1) {
172
+ yield
173
+ }
174
+ }
175
+ end
85
176
  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.final_value : nil
177
+
178
+ # Call each before hook, and if they all succeed, yield.
179
+ # If they don't all succeed, call after_ for each one that succeeded.
180
+ def call_hooks(instrumenters, object, before_hook_name, after_hook_name)
181
+ begin
182
+ successful = []
183
+ instrumenters.each do |instrumenter|
184
+ instrumenter.public_send(before_hook_name, object)
185
+ successful << instrumenter
186
+ end
187
+
188
+ # if any before hooks raise an exception, quit calling before hooks,
189
+ # but call the after hooks on anything that succeeded but also
190
+ # raise the exception that came from the before hook.
191
+ rescue GraphQL::ExecutionError => err
192
+ object.context.errors << err
193
+ rescue => e
194
+ raise call_after_hooks(successful, object, after_hook_name, e)
195
+ end
196
+
197
+ begin
198
+ yield # Call the user code
199
+ ensure
200
+ ex = call_after_hooks(successful, object, after_hook_name, nil)
201
+ raise ex if ex
202
+ end
91
203
  end
92
- final_values.compact!
93
- tracer.trace("execute_query_lazy", {multiplex: multiplex, query: query}) do
94
- Interpreter::Resolve.resolve_all(final_values)
204
+
205
+ def call_after_hooks(instrumenters, object, after_hook_name, ex)
206
+ instrumenters.reverse_each do |instrumenter|
207
+ begin
208
+ instrumenter.public_send(after_hook_name, object)
209
+ rescue => e
210
+ ex = e
211
+ end
212
+ end
213
+ ex
214
+ end
215
+ end
216
+
217
+ class ListResultFailedError < GraphQL::Error
218
+ def initialize(value:, path:, field:)
219
+ message = "Failed to build a GraphQL list result for field `#{field.path}` at path `#{path.join(".")}`.\n".dup
220
+
221
+ message << "Expected `#{value.inspect}` (#{value.class}) to implement `.each` to satisfy the GraphQL return type `#{field.type.to_type_signature}`.\n"
222
+
223
+ if field.connection?
224
+ message << "\nThis field was treated as a Relay-style connection; add `connection: false` to the `field(...)` to disable this behavior."
225
+ end
226
+ super(message)
95
227
  end
96
228
  end
97
229
  end
@@ -36,6 +36,10 @@ module GraphQL
36
36
  @storage.compute_if_absent(value.class) { find_superclass_method(value.class) }
37
37
  end
38
38
 
39
+ def each
40
+ @storage.each_pair { |k, v| yield(k, v) }
41
+ end
42
+
39
43
  protected
40
44
 
41
45
  attr_reader :storage
@@ -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
@@ -51,7 +51,17 @@ module GraphQL
51
51
 
52
52
  # @return [Hash<Symbol, Object>]
53
53
  def arguments
54
- @arguments ||= @field && ArgumentHelpers.arguments(@query, nil, @field, ast_nodes.first)
54
+ if defined?(@arguments)
55
+ @arguments
56
+ else
57
+ @arguments = if @field
58
+ @query.schema.after_lazy(@query.arguments_for(@ast_nodes.first, @field)) do |args|
59
+ args.is_a?(Execution::Interpreter::Arguments) ? args.keyword_arguments : args
60
+ end
61
+ else
62
+ nil
63
+ end
64
+ end
55
65
  end
56
66
 
57
67
  # True if this node has a selection on `field_name`.
@@ -66,8 +76,8 @@ module GraphQL
66
76
  # @param field_name [String, Symbol]
67
77
  # @param arguments [Hash] Arguments which must match in the selection
68
78
  # @return [Boolean]
69
- def selects?(field_name, arguments: nil)
70
- 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?
71
81
  end
72
82
 
73
83
  # @return [Boolean] True if this lookahead represents a field that was requested
@@ -77,16 +87,39 @@ module GraphQL
77
87
 
78
88
  # Like {#selects?}, but can be used for chaining.
79
89
  # It returns a null object (check with {#selected?})
90
+ # @param field_name [String, Symbol]
80
91
  # @return [GraphQL::Execution::Lookahead]
81
92
  def selection(field_name, selected_type: @selected_type, arguments: nil)
82
- next_field_name = normalize_name(field_name)
93
+ next_field_defn = case field_name
94
+ when String
95
+ @query.get_field(selected_type, field_name)
96
+ when Symbol
97
+ # Try to avoid the `.to_s` below, if possible
98
+ all_fields = if selected_type.kind.fields?
99
+ @query.warden.fields(selected_type)
100
+ else
101
+ # Handle unions by checking possible
102
+ @query.warden
103
+ .possible_types(selected_type)
104
+ .map { |t| @query.warden.fields(t) }
105
+ .flatten
106
+ end
107
+
108
+ if (match_by_orig_name = all_fields.find { |f| f.original_name == field_name })
109
+ match_by_orig_name
110
+ else
111
+ # Symbol#name is only present on 3.0+
112
+ sym_s = field_name.respond_to?(:name) ? field_name.name : field_name.to_s
113
+ guessed_name = Schema::Member::BuildType.camelize(sym_s)
114
+ @query.get_field(selected_type, guessed_name)
115
+ end
116
+ end
83
117
 
84
- next_field_defn = FieldHelpers.get_field(@query.schema, selected_type, next_field_name)
85
118
  if next_field_defn
86
119
  next_nodes = []
87
120
  @ast_nodes.each do |ast_node|
88
121
  ast_node.selections.each do |selection|
89
- find_selected_nodes(selection, next_field_name, next_field_defn, arguments: arguments, matches: next_nodes)
122
+ find_selected_nodes(selection, next_field_defn, arguments: arguments, matches: next_nodes)
90
123
  end
91
124
  end
92
125
 
@@ -127,7 +160,7 @@ module GraphQL
127
160
 
128
161
  subselections_by_type.each do |type, ast_nodes_by_response_key|
129
162
  ast_nodes_by_response_key.each do |response_key, ast_nodes|
130
- field_defn = FieldHelpers.get_field(@query.schema, type, ast_nodes.first.name)
163
+ field_defn = @query.get_field(type, ast_nodes.first.name)
131
164
  lookahead = Lookahead.new(query: @query, ast_nodes: ast_nodes, field: field_defn, owner_type: type)
132
165
  subselections.push(lookahead)
133
166
  end
@@ -186,25 +219,22 @@ module GraphQL
186
219
 
187
220
  private
188
221
 
189
- # If it's a symbol, stringify and camelize it
190
- def normalize_name(name)
191
- if name.is_a?(Symbol)
192
- Schema::Member::BuildType.camelize(name.to_s)
193
- else
194
- name
195
- end
196
- end
197
-
198
- def normalize_keyword(keyword)
199
- if keyword.is_a?(String)
200
- Schema::Member::BuildType.underscore(keyword).to_sym
201
- else
202
- keyword
222
+ def skipped_by_directive?(ast_selection)
223
+ ast_selection.directives.each do |directive|
224
+ dir_defn = @query.schema.directives.fetch(directive.name)
225
+ directive_class = dir_defn
226
+ if directive_class
227
+ dir_args = @query.arguments_for(directive, dir_defn)
228
+ return true unless directive_class.static_include?(dir_args, @query.context)
229
+ end
203
230
  end
231
+ false
204
232
  end
205
233
 
206
234
  def find_selections(subselections_by_type, selections_on_type, selected_type, ast_selections, arguments)
207
235
  ast_selections.each do |ast_selection|
236
+ next if skipped_by_directive?(ast_selection)
237
+
208
238
  case ast_selection
209
239
  when GraphQL::Language::Nodes::Field
210
240
  response_key = ast_selection.alias || ast_selection.name
@@ -213,7 +243,7 @@ module GraphQL
213
243
  elsif arguments.nil? || arguments.empty?
214
244
  selections_on_type[response_key] = [ast_selection]
215
245
  else
216
- field_defn = FieldHelpers.get_field(@query.schema, selected_type, ast_selection.name)
246
+ field_defn = @query.get_field(selected_type, ast_selection.name)
217
247
  if arguments_match?(arguments, field_defn, ast_selection)
218
248
  selections_on_type[response_key] = [ast_selection]
219
249
  end
@@ -223,14 +253,14 @@ module GraphQL
223
253
  subselections_on_type = selections_on_type
224
254
  if (t = ast_selection.type)
225
255
  # Assuming this is valid, that `t` will be found.
226
- on_type = @query.schema.types[t.name].metadata[:type_class]
256
+ on_type = @query.get_type(t.name)
227
257
  subselections_on_type = subselections_by_type[on_type] ||= {}
228
258
  end
229
259
  find_selections(subselections_by_type, subselections_on_type, on_type, ast_selection.selections, arguments)
230
260
  when GraphQL::Language::Nodes::FragmentSpread
231
261
  frag_defn = @query.fragments[ast_selection.name] || raise("Invariant: Can't look ahead to nonexistent fragment #{ast_selection.name} (found: #{@query.fragments.keys})")
232
262
  # Again, assuming a valid AST
233
- on_type = @query.schema.types[frag_defn.type.name].metadata[:type_class]
263
+ on_type = @query.get_type(frag_defn.type.name)
234
264
  subselections_on_type = subselections_by_type[on_type] ||= {}
235
265
  find_selections(subselections_by_type, subselections_on_type, on_type, frag_defn.selections, arguments)
236
266
  else
@@ -241,10 +271,11 @@ module GraphQL
241
271
 
242
272
  # If a selection on `node` matches `field_name` (which is backed by `field_defn`)
243
273
  # and matches the `arguments:` constraints, then add that node to `matches`
244
- def find_selected_nodes(node, field_name, field_defn, arguments:, matches:)
274
+ def find_selected_nodes(node, field_defn, arguments:, matches:)
275
+ return if skipped_by_directive?(node)
245
276
  case node
246
277
  when GraphQL::Language::Nodes::Field
247
- if node.name == field_name
278
+ if node.name == field_defn.graphql_name
248
279
  if arguments.nil? || arguments.empty?
249
280
  # No constraint applied
250
281
  matches << node
@@ -253,128 +284,26 @@ module GraphQL
253
284
  end
254
285
  end
255
286
  when GraphQL::Language::Nodes::InlineFragment
256
- node.selections.each { |s| find_selected_nodes(s, field_name, field_defn, arguments: arguments, matches: matches) }
287
+ node.selections.each { |s| find_selected_nodes(s, field_defn, arguments: arguments, matches: matches) }
257
288
  when GraphQL::Language::Nodes::FragmentSpread
258
289
  frag_defn = @query.fragments[node.name] || raise("Invariant: Can't look ahead to nonexistent fragment #{node.name} (found: #{@query.fragments.keys})")
259
- frag_defn.selections.each { |s| find_selected_nodes(s, field_name, field_defn, arguments: arguments, matches: matches) }
290
+ frag_defn.selections.each { |s| find_selected_nodes(s, field_defn, arguments: arguments, matches: matches) }
260
291
  else
261
292
  raise "Unexpected selection comparison on #{node.class.name} (#{node})"
262
293
  end
263
294
  end
264
295
 
265
296
  def arguments_match?(arguments, field_defn, field_node)
266
- query_kwargs = ArgumentHelpers.arguments(@query, nil, field_defn, field_node)
297
+ query_kwargs = @query.arguments_for(field_node, field_defn)
267
298
  arguments.all? do |arg_name, arg_value|
268
- arg_name = normalize_keyword(arg_name)
269
- # Make sure the constraint is present with a matching value
270
- query_kwargs.key?(arg_name) && query_kwargs[arg_name] == arg_value
271
- end
272
- end
273
-
274
- # TODO Dedup with interpreter
275
- module ArgumentHelpers
276
- module_function
277
-
278
- def arguments(query, graphql_object, arg_owner, ast_node)
279
- kwarg_arguments = {}
280
- arg_defns = arg_owner.arguments
281
- ast_node.arguments.each do |arg|
282
- arg_defn = arg_defns[arg.name] || raise("Invariant: missing argument definition for #{arg.name.inspect} in #{arg_defns.keys} from #{arg_owner}")
283
- # Need to distinguish between client-provided `nil`
284
- # and nothing-at-all
285
- is_present, value = arg_to_value(query, graphql_object, arg_defn.type, arg.value)
286
- if is_present
287
- # This doesn't apply to directives, which are legacy
288
- # Can remove this when Skip and Include use classes or something.
289
- if graphql_object
290
- value = arg_defn.prepare_value(graphql_object, value)
291
- end
292
- kwarg_arguments[arg_defn.keyword] = value
293
- end
294
- end
295
- arg_defns.each do |name, arg_defn|
296
- if arg_defn.default_value? && !kwarg_arguments.key?(arg_defn.keyword)
297
- kwarg_arguments[arg_defn.keyword] = arg_defn.default_value
298
- end
299
- end
300
- kwarg_arguments
301
- end
302
-
303
- # Get a Ruby-ready value from a client query.
304
- # @param graphql_object [Object] The owner of the field whose argument this is
305
- # @param arg_type [Class, GraphQL::Schema::NonNull, GraphQL::Schema::List]
306
- # @param ast_value [GraphQL::Language::Nodes::VariableIdentifier, String, Integer, Float, Boolean]
307
- # @return [Array(is_present, value)]
308
- def arg_to_value(query, graphql_object, arg_type, ast_value)
309
- if ast_value.is_a?(GraphQL::Language::Nodes::VariableIdentifier)
310
- # If it's not here, it will get added later
311
- if query.variables.key?(ast_value.name)
312
- return true, query.variables[ast_value.name]
313
- else
314
- return false, nil
315
- end
316
- elsif ast_value.is_a?(GraphQL::Language::Nodes::NullValue)
317
- return true, nil
318
- elsif arg_type.is_a?(GraphQL::Schema::NonNull)
319
- arg_to_value(query, graphql_object, arg_type.of_type, ast_value)
320
- elsif arg_type.is_a?(GraphQL::Schema::List)
321
- # Treat a single value like a list
322
- arg_value = Array(ast_value)
323
- list = []
324
- arg_value.map do |inner_v|
325
- _present, value = arg_to_value(query, graphql_object, arg_type.of_type, inner_v)
326
- list << value
327
- end
328
- return true, list
329
- elsif arg_type.is_a?(Class) && arg_type < GraphQL::Schema::InputObject
330
- # For these, `prepare` is applied during `#initialize`.
331
- # Pass `nil` so it will be skipped in `#arguments`.
332
- # What a mess.
333
- args = arguments(query, nil, arg_type, ast_value)
334
- # We're not tracking defaults_used, but for our purposes
335
- # we compare the value to the default value.
336
- return true, arg_type.new(ruby_kwargs: args, context: query.context, defaults_used: nil)
337
- else
338
- flat_value = flatten_ast_value(query, ast_value)
339
- return true, arg_type.coerce_input(flat_value, query.context)
340
- end
341
- end
342
-
343
- def flatten_ast_value(query, v)
344
- case v
345
- when GraphQL::Language::Nodes::Enum
346
- v.name
347
- when GraphQL::Language::Nodes::InputObject
348
- h = {}
349
- v.arguments.each do |arg|
350
- h[arg.name] = flatten_ast_value(query, arg.value)
351
- end
352
- h
353
- when Array
354
- v.map { |v2| flatten_ast_value(query, v2) }
355
- when GraphQL::Language::Nodes::VariableIdentifier
356
- flatten_ast_value(query.variables[v.name])
357
- else
358
- v
359
- end
360
- end
361
- end
362
-
363
- # TODO dedup with interpreter
364
- module FieldHelpers
365
- module_function
366
-
367
- def get_field(schema, owner_type, field_name)
368
- field_defn = owner_type.get_field(field_name)
369
- field_defn ||= if owner_type == schema.query.metadata[:type_class] && (entry_point_field = schema.introspection_system.entry_point(name: field_name))
370
- entry_point_field.metadata[:type_class]
371
- elsif (dynamic_field = schema.introspection_system.dynamic_field(name: field_name))
372
- dynamic_field.metadata[:type_class]
299
+ arg_name_sym = if arg_name.is_a?(String)
300
+ Schema::Member::BuildType.underscore(arg_name).to_sym
373
301
  else
374
- nil
302
+ arg_name
375
303
  end
376
304
 
377
- field_defn
305
+ # Make sure the constraint is present with a matching value
306
+ query_kwargs.key?(arg_name_sym) && query_kwargs[arg_name_sym] == arg_value
378
307
  end
379
308
  end
380
309
  end