graphql 1.13.24 → 2.5.11

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (427) hide show
  1. checksums.yaml +4 -4
  2. data/lib/generators/graphql/install/mutation_root_generator.rb +2 -2
  3. data/lib/generators/graphql/install/templates/base_mutation.erb +2 -0
  4. data/lib/generators/graphql/install/templates/mutation_type.erb +2 -0
  5. data/lib/generators/graphql/install_generator.rb +50 -1
  6. data/lib/generators/graphql/mutation_delete_generator.rb +1 -1
  7. data/lib/generators/graphql/mutation_update_generator.rb +1 -1
  8. data/lib/generators/graphql/orm_mutations_base.rb +1 -1
  9. data/lib/generators/graphql/relay.rb +21 -18
  10. data/lib/generators/graphql/templates/base_argument.erb +2 -0
  11. data/lib/generators/graphql/templates/base_connection.erb +2 -0
  12. data/lib/generators/graphql/templates/base_edge.erb +2 -0
  13. data/lib/generators/graphql/templates/base_enum.erb +2 -0
  14. data/lib/generators/graphql/templates/base_field.erb +2 -0
  15. data/lib/generators/graphql/templates/base_input_object.erb +2 -0
  16. data/lib/generators/graphql/templates/base_interface.erb +2 -0
  17. data/lib/generators/graphql/templates/base_object.erb +2 -0
  18. data/lib/generators/graphql/templates/base_resolver.erb +8 -0
  19. data/lib/generators/graphql/templates/base_scalar.erb +2 -0
  20. data/lib/generators/graphql/templates/base_union.erb +2 -0
  21. data/lib/generators/graphql/templates/graphql_controller.erb +2 -0
  22. data/lib/generators/graphql/templates/loader.erb +2 -0
  23. data/lib/generators/graphql/templates/mutation.erb +2 -0
  24. data/lib/generators/graphql/templates/node_type.erb +2 -0
  25. data/lib/generators/graphql/templates/query_type.erb +2 -0
  26. data/lib/generators/graphql/templates/schema.erb +8 -0
  27. data/lib/generators/graphql/type_generator.rb +1 -1
  28. data/lib/graphql/analysis/analyzer.rb +90 -0
  29. data/lib/graphql/analysis/field_usage.rb +65 -28
  30. data/lib/graphql/analysis/max_query_complexity.rb +11 -17
  31. data/lib/graphql/analysis/max_query_depth.rb +13 -19
  32. data/lib/graphql/analysis/query_complexity.rb +236 -61
  33. data/lib/graphql/analysis/query_depth.rb +38 -23
  34. data/lib/graphql/analysis/visitor.rb +280 -0
  35. data/lib/graphql/analysis.rb +93 -6
  36. data/lib/graphql/autoload.rb +38 -0
  37. data/lib/graphql/backtrace/table.rb +118 -73
  38. data/lib/graphql/backtrace.rb +2 -25
  39. data/lib/graphql/coercion_error.rb +1 -9
  40. data/lib/graphql/current.rb +57 -0
  41. data/lib/graphql/dashboard/detailed_traces.rb +47 -0
  42. data/lib/graphql/dashboard/installable.rb +22 -0
  43. data/lib/graphql/dashboard/limiters.rb +93 -0
  44. data/lib/graphql/dashboard/operation_store.rb +199 -0
  45. data/lib/graphql/dashboard/statics/bootstrap-5.3.3.min.css +6 -0
  46. data/lib/graphql/dashboard/statics/bootstrap-5.3.3.min.js +7 -0
  47. data/lib/graphql/dashboard/statics/charts.min.css +1 -0
  48. data/lib/graphql/dashboard/statics/dashboard.css +30 -0
  49. data/lib/graphql/dashboard/statics/dashboard.js +143 -0
  50. data/lib/graphql/dashboard/statics/header-icon.png +0 -0
  51. data/lib/graphql/dashboard/statics/icon.png +0 -0
  52. data/lib/graphql/dashboard/subscriptions.rb +96 -0
  53. data/lib/graphql/dashboard/views/graphql/dashboard/detailed_traces/traces/index.html.erb +45 -0
  54. data/lib/graphql/dashboard/views/graphql/dashboard/landings/show.html.erb +18 -0
  55. data/lib/graphql/dashboard/views/graphql/dashboard/limiters/limiters/show.html.erb +62 -0
  56. data/lib/graphql/dashboard/views/graphql/dashboard/not_installed.html.erb +18 -0
  57. data/lib/graphql/dashboard/views/graphql/dashboard/operation_store/clients/_form.html.erb +23 -0
  58. data/lib/graphql/dashboard/views/graphql/dashboard/operation_store/clients/edit.html.erb +21 -0
  59. data/lib/graphql/dashboard/views/graphql/dashboard/operation_store/clients/index.html.erb +69 -0
  60. data/lib/graphql/dashboard/views/graphql/dashboard/operation_store/clients/new.html.erb +7 -0
  61. data/lib/graphql/dashboard/views/graphql/dashboard/operation_store/index_entries/index.html.erb +39 -0
  62. data/lib/graphql/dashboard/views/graphql/dashboard/operation_store/index_entries/show.html.erb +32 -0
  63. data/lib/graphql/dashboard/views/graphql/dashboard/operation_store/operations/index.html.erb +81 -0
  64. data/lib/graphql/dashboard/views/graphql/dashboard/operation_store/operations/show.html.erb +71 -0
  65. data/lib/graphql/dashboard/views/graphql/dashboard/subscriptions/subscriptions/show.html.erb +41 -0
  66. data/lib/graphql/dashboard/views/graphql/dashboard/subscriptions/topics/index.html.erb +55 -0
  67. data/lib/graphql/dashboard/views/graphql/dashboard/subscriptions/topics/show.html.erb +40 -0
  68. data/lib/graphql/dashboard/views/layouts/graphql/dashboard/application.html.erb +108 -0
  69. data/lib/graphql/dashboard.rb +158 -0
  70. data/lib/graphql/dataloader/active_record_association_source.rb +84 -0
  71. data/lib/graphql/dataloader/active_record_source.rb +47 -0
  72. data/lib/graphql/dataloader/async_dataloader.rb +101 -0
  73. data/lib/graphql/dataloader/null_dataloader.rb +11 -2
  74. data/lib/graphql/dataloader/request.rb +5 -0
  75. data/lib/graphql/dataloader/source.rb +103 -47
  76. data/lib/graphql/dataloader.rb +174 -148
  77. data/lib/graphql/dig.rb +3 -2
  78. data/lib/graphql/duration_encoding_error.rb +16 -0
  79. data/lib/graphql/execution/errors.rb +12 -82
  80. data/lib/graphql/execution/interpreter/argument_value.rb +5 -1
  81. data/lib/graphql/execution/interpreter/arguments.rb +1 -1
  82. data/lib/graphql/execution/interpreter/arguments_cache.rb +30 -35
  83. data/lib/graphql/execution/interpreter/resolve.rb +32 -2
  84. data/lib/graphql/execution/interpreter/runtime/graphql_result.rb +215 -0
  85. data/lib/graphql/execution/interpreter/runtime.rb +525 -502
  86. data/lib/graphql/execution/interpreter.rb +127 -81
  87. data/lib/graphql/execution/lazy.rb +7 -21
  88. data/lib/graphql/execution/lookahead.rb +133 -55
  89. data/lib/graphql/execution/multiplex.rb +6 -176
  90. data/lib/graphql/execution.rb +11 -4
  91. data/lib/graphql/introspection/directive_location_enum.rb +1 -1
  92. data/lib/graphql/introspection/directive_type.rb +1 -1
  93. data/lib/graphql/introspection/dynamic_fields.rb +3 -8
  94. data/lib/graphql/introspection/entry_points.rb +10 -17
  95. data/lib/graphql/introspection/field_type.rb +1 -1
  96. data/lib/graphql/introspection/schema_type.rb +8 -11
  97. data/lib/graphql/introspection/type_type.rb +13 -6
  98. data/lib/graphql/introspection.rb +4 -3
  99. data/lib/graphql/invalid_name_error.rb +1 -1
  100. data/lib/graphql/invalid_null_error.rb +20 -17
  101. data/lib/graphql/language/block_string.rb +34 -18
  102. data/lib/graphql/language/cache.rb +13 -0
  103. data/lib/graphql/language/comment.rb +18 -0
  104. data/lib/graphql/language/definition_slice.rb +1 -1
  105. data/lib/graphql/language/document_from_schema_definition.rb +114 -80
  106. data/lib/graphql/language/lexer.rb +375 -1489
  107. data/lib/graphql/language/nodes.rb +189 -104
  108. data/lib/graphql/language/parser.rb +807 -1941
  109. data/lib/graphql/language/printer.rb +366 -163
  110. data/lib/graphql/language/sanitized_printer.rb +21 -23
  111. data/lib/graphql/language/static_visitor.rb +171 -0
  112. data/lib/graphql/language/visitor.rb +189 -138
  113. data/lib/graphql/language.rb +62 -1
  114. data/lib/graphql/load_application_object_failed_error.rb +5 -1
  115. data/lib/graphql/pagination/active_record_relation_connection.rb +0 -8
  116. data/lib/graphql/pagination/array_connection.rb +8 -6
  117. data/lib/graphql/pagination/connection.rb +61 -7
  118. data/lib/graphql/pagination/connections.rb +3 -28
  119. data/lib/graphql/pagination/mongoid_relation_connection.rb +1 -2
  120. data/lib/graphql/pagination/relation_connection.rb +2 -0
  121. data/lib/graphql/query/context/scoped_context.rb +101 -0
  122. data/lib/graphql/query/context.rb +131 -225
  123. data/lib/graphql/query/input_validation_result.rb +1 -1
  124. data/lib/graphql/query/null_context.rb +11 -33
  125. data/lib/graphql/query/partial.rb +179 -0
  126. data/lib/graphql/query/validation_pipeline.rb +14 -37
  127. data/lib/graphql/query/variable_validation_error.rb +1 -1
  128. data/lib/graphql/query/variables.rb +6 -19
  129. data/lib/graphql/query.rb +162 -98
  130. data/lib/graphql/railtie.rb +15 -109
  131. data/lib/graphql/rake_task/validate.rb +1 -1
  132. data/lib/graphql/rake_task.rb +30 -11
  133. data/lib/graphql/relay/range_add.rb +9 -20
  134. data/lib/graphql/relay.rb +0 -15
  135. data/lib/graphql/rubocop/graphql/base_cop.rb +1 -1
  136. data/lib/graphql/rubocop/graphql/field_type_in_block.rb +144 -0
  137. data/lib/graphql/rubocop/graphql/root_types_in_block.rb +38 -0
  138. data/lib/graphql/rubocop.rb +2 -0
  139. data/lib/graphql/schema/addition.rb +70 -33
  140. data/lib/graphql/schema/always_visible.rb +15 -0
  141. data/lib/graphql/schema/argument.rb +104 -59
  142. data/lib/graphql/schema/base_64_encoder.rb +3 -5
  143. data/lib/graphql/schema/build_from_definition.rb +154 -74
  144. data/lib/graphql/schema/directive/flagged.rb +4 -2
  145. data/lib/graphql/schema/directive/one_of.rb +24 -0
  146. data/lib/graphql/schema/directive/specified_by.rb +14 -0
  147. data/lib/graphql/schema/directive/transform.rb +1 -1
  148. data/lib/graphql/schema/directive.rb +47 -24
  149. data/lib/graphql/schema/enum.rb +137 -65
  150. data/lib/graphql/schema/enum_value.rb +11 -26
  151. data/lib/graphql/schema/field/connection_extension.rb +6 -16
  152. data/lib/graphql/schema/field/scope_extension.rb +8 -1
  153. data/lib/graphql/schema/field.rb +399 -404
  154. data/lib/graphql/schema/field_extension.rb +2 -5
  155. data/lib/graphql/schema/find_inherited_value.rb +2 -7
  156. data/lib/graphql/schema/has_single_input_argument.rb +160 -0
  157. data/lib/graphql/schema/input_object.rb +144 -99
  158. data/lib/graphql/schema/interface.rb +34 -51
  159. data/lib/graphql/schema/introspection_system.rb +12 -26
  160. data/lib/graphql/schema/late_bound_type.rb +12 -2
  161. data/lib/graphql/schema/list.rb +3 -9
  162. data/lib/graphql/schema/loader.rb +4 -6
  163. data/lib/graphql/schema/member/base_dsl_methods.rb +32 -18
  164. data/lib/graphql/schema/member/build_type.rb +15 -9
  165. data/lib/graphql/schema/member/has_arguments.rb +192 -96
  166. data/lib/graphql/schema/member/has_ast_node.rb +12 -0
  167. data/lib/graphql/schema/member/has_dataloader.rb +62 -0
  168. data/lib/graphql/schema/member/has_deprecation_reason.rb +18 -4
  169. data/lib/graphql/schema/member/has_directives.rb +81 -61
  170. data/lib/graphql/schema/member/has_fields.rb +119 -39
  171. data/lib/graphql/schema/member/has_interfaces.rb +66 -23
  172. data/lib/graphql/schema/member/has_unresolved_type_error.rb +5 -1
  173. data/lib/graphql/schema/member/has_validators.rb +32 -6
  174. data/lib/graphql/schema/member/relay_shortcuts.rb +47 -2
  175. data/lib/graphql/schema/member/scoped.rb +19 -0
  176. data/lib/graphql/schema/member/type_system_helpers.rb +32 -2
  177. data/lib/graphql/schema/member/validates_input.rb +4 -4
  178. data/lib/graphql/schema/member.rb +1 -6
  179. data/lib/graphql/schema/mutation.rb +7 -9
  180. data/lib/graphql/schema/non_null.rb +1 -7
  181. data/lib/graphql/schema/object.rb +42 -49
  182. data/lib/graphql/schema/printer.rb +12 -8
  183. data/lib/graphql/schema/ractor_shareable.rb +79 -0
  184. data/lib/graphql/schema/relay_classic_mutation.rb +12 -124
  185. data/lib/graphql/schema/resolver/has_payload_type.rb +20 -10
  186. data/lib/graphql/schema/resolver.rb +96 -81
  187. data/lib/graphql/schema/scalar.rb +10 -30
  188. data/lib/graphql/schema/subscription.rb +60 -14
  189. data/lib/graphql/schema/timeout.rb +44 -31
  190. data/lib/graphql/schema/type_expression.rb +2 -2
  191. data/lib/graphql/schema/type_membership.rb +3 -0
  192. data/lib/graphql/schema/union.rb +12 -19
  193. data/lib/graphql/schema/unique_within_type.rb +1 -1
  194. data/lib/graphql/schema/validator/all_validator.rb +62 -0
  195. data/lib/graphql/schema/validator/required_validator.rb +60 -10
  196. data/lib/graphql/schema/validator.rb +5 -3
  197. data/lib/graphql/schema/visibility/migration.rb +188 -0
  198. data/lib/graphql/schema/visibility/profile.rb +445 -0
  199. data/lib/graphql/schema/visibility/visit.rb +190 -0
  200. data/lib/graphql/schema/visibility.rb +311 -0
  201. data/lib/graphql/schema/warden.rb +318 -94
  202. data/lib/graphql/schema/wrapper.rb +0 -5
  203. data/lib/graphql/schema.rb +1148 -1085
  204. data/lib/graphql/static_validation/all_rules.rb +4 -3
  205. data/lib/graphql/static_validation/base_visitor.rb +11 -27
  206. data/lib/graphql/static_validation/definition_dependencies.rb +7 -1
  207. data/lib/graphql/static_validation/error.rb +2 -2
  208. data/lib/graphql/static_validation/literal_validator.rb +24 -7
  209. data/lib/graphql/static_validation/rules/argument_literals_are_compatible.rb +1 -1
  210. data/lib/graphql/static_validation/rules/argument_names_are_unique.rb +1 -1
  211. data/lib/graphql/static_validation/rules/arguments_are_defined.rb +3 -2
  212. data/lib/graphql/static_validation/rules/directives_are_defined.rb +13 -7
  213. data/lib/graphql/static_validation/rules/directives_are_in_valid_locations.rb +14 -12
  214. data/lib/graphql/static_validation/rules/fields_are_defined_on_type.rb +12 -2
  215. data/lib/graphql/static_validation/rules/fields_have_appropriate_selections.rb +48 -6
  216. data/lib/graphql/static_validation/rules/fields_will_merge.rb +90 -27
  217. data/lib/graphql/static_validation/rules/fields_will_merge_error.rb +10 -2
  218. data/lib/graphql/static_validation/rules/fragment_spreads_are_possible.rb +3 -3
  219. data/lib/graphql/static_validation/rules/fragment_types_exist.rb +12 -2
  220. data/lib/graphql/static_validation/rules/fragments_are_on_composite_types.rb +1 -1
  221. data/lib/graphql/static_validation/rules/mutation_root_exists.rb +1 -1
  222. data/lib/graphql/static_validation/rules/no_definitions_are_present.rb +1 -1
  223. data/lib/graphql/static_validation/rules/not_single_subscription_error.rb +25 -0
  224. data/lib/graphql/static_validation/rules/one_of_input_objects_are_valid.rb +66 -0
  225. data/lib/graphql/static_validation/rules/one_of_input_objects_are_valid_error.rb +29 -0
  226. data/lib/graphql/static_validation/rules/query_root_exists.rb +1 -1
  227. data/lib/graphql/static_validation/rules/required_arguments_are_present.rb +5 -5
  228. data/lib/graphql/static_validation/rules/required_input_object_attributes_are_present.rb +5 -5
  229. data/lib/graphql/static_validation/rules/subscription_root_exists_and_single_subscription_selection.rb +26 -0
  230. data/lib/graphql/static_validation/rules/unique_directives_per_location.rb +19 -9
  231. data/lib/graphql/static_validation/rules/variable_default_values_are_correctly_typed.rb +18 -27
  232. data/lib/graphql/static_validation/rules/variable_names_are_unique.rb +1 -1
  233. data/lib/graphql/static_validation/rules/variable_usages_are_allowed.rb +2 -2
  234. data/lib/graphql/static_validation/rules/variables_are_input_types.rb +11 -2
  235. data/lib/graphql/static_validation/validation_context.rb +21 -5
  236. data/lib/graphql/static_validation/validator.rb +12 -26
  237. data/lib/graphql/static_validation.rb +0 -3
  238. data/lib/graphql/subscriptions/action_cable_subscriptions.rb +14 -6
  239. data/lib/graphql/subscriptions/broadcast_analyzer.rb +11 -5
  240. data/lib/graphql/subscriptions/default_subscription_resolve_extension.rb +40 -1
  241. data/lib/graphql/subscriptions/event.rb +24 -12
  242. data/lib/graphql/subscriptions/serialize.rb +3 -1
  243. data/lib/graphql/subscriptions.rb +48 -32
  244. data/lib/graphql/testing/helpers.rb +158 -0
  245. data/lib/graphql/testing.rb +2 -0
  246. data/lib/graphql/tracing/active_support_notifications_trace.rb +27 -0
  247. data/lib/graphql/tracing/active_support_notifications_tracing.rb +1 -1
  248. data/lib/graphql/tracing/appoptics_trace.rb +259 -0
  249. data/lib/graphql/tracing/appoptics_tracing.rb +9 -2
  250. data/lib/graphql/tracing/appsignal_trace.rb +54 -0
  251. data/lib/graphql/tracing/appsignal_tracing.rb +2 -0
  252. data/lib/graphql/tracing/call_legacy_tracers.rb +66 -0
  253. data/lib/graphql/tracing/data_dog_trace.rb +71 -0
  254. data/lib/graphql/tracing/data_dog_tracing.rb +3 -0
  255. data/lib/graphql/tracing/detailed_trace/memory_backend.rb +60 -0
  256. data/lib/graphql/tracing/detailed_trace/redis_backend.rb +72 -0
  257. data/lib/graphql/tracing/detailed_trace.rb +93 -0
  258. data/lib/graphql/{execution/instrumentation.rb → tracing/legacy_hooks_trace.rb} +11 -28
  259. data/lib/graphql/tracing/legacy_trace.rb +12 -0
  260. data/lib/graphql/tracing/monitor_trace.rb +283 -0
  261. data/lib/graphql/tracing/new_relic_trace.rb +68 -0
  262. data/lib/graphql/tracing/new_relic_tracing.rb +2 -0
  263. data/lib/graphql/tracing/notifications_trace.rb +195 -0
  264. data/lib/graphql/tracing/notifications_tracing.rb +2 -0
  265. data/lib/graphql/tracing/null_trace.rb +9 -0
  266. data/lib/graphql/tracing/perfetto_trace/trace.proto +141 -0
  267. data/lib/graphql/tracing/perfetto_trace/trace_pb.rb +33 -0
  268. data/lib/graphql/tracing/perfetto_trace.rb +734 -0
  269. data/lib/graphql/tracing/platform_trace.rb +123 -0
  270. data/lib/graphql/tracing/platform_tracing.rb +28 -41
  271. data/lib/graphql/tracing/{prometheus_tracing → prometheus_trace}/graphql_collector.rb +6 -2
  272. data/lib/graphql/tracing/prometheus_trace.rb +93 -0
  273. data/lib/graphql/tracing/prometheus_tracing.rb +5 -3
  274. data/lib/graphql/tracing/scout_trace.rb +49 -0
  275. data/lib/graphql/tracing/scout_tracing.rb +2 -0
  276. data/lib/graphql/tracing/sentry_trace.rb +80 -0
  277. data/lib/graphql/tracing/statsd_trace.rb +48 -0
  278. data/lib/graphql/tracing/statsd_tracing.rb +2 -0
  279. data/lib/graphql/tracing/trace.rb +186 -0
  280. data/lib/graphql/tracing.rb +32 -52
  281. data/lib/graphql/type_kinds.rb +8 -4
  282. data/lib/graphql/types/iso_8601_date.rb +4 -1
  283. data/lib/graphql/types/iso_8601_date_time.rb +4 -0
  284. data/lib/graphql/types/iso_8601_duration.rb +77 -0
  285. data/lib/graphql/types/relay/base_connection.rb +16 -6
  286. data/lib/graphql/types/relay/connection_behaviors.rb +65 -23
  287. data/lib/graphql/types/relay/edge_behaviors.rb +33 -5
  288. data/lib/graphql/types/relay/node_behaviors.rb +12 -2
  289. data/lib/graphql/types/relay/page_info_behaviors.rb +11 -2
  290. data/lib/graphql/types/relay.rb +0 -3
  291. data/lib/graphql/types/string.rb +1 -1
  292. data/lib/graphql/types.rb +18 -10
  293. data/lib/graphql/unauthorized_enum_value_error.rb +13 -0
  294. data/lib/graphql/version.rb +1 -1
  295. data/lib/graphql.rb +76 -123
  296. data/readme.md +13 -3
  297. metadata +225 -142
  298. data/lib/graphql/analysis/analyze_query.rb +0 -98
  299. data/lib/graphql/analysis/ast/analyzer.rb +0 -84
  300. data/lib/graphql/analysis/ast/field_usage.rb +0 -55
  301. data/lib/graphql/analysis/ast/max_query_complexity.rb +0 -23
  302. data/lib/graphql/analysis/ast/max_query_depth.rb +0 -22
  303. data/lib/graphql/analysis/ast/query_complexity.rb +0 -230
  304. data/lib/graphql/analysis/ast/query_depth.rb +0 -56
  305. data/lib/graphql/analysis/ast/visitor.rb +0 -269
  306. data/lib/graphql/analysis/ast.rb +0 -91
  307. data/lib/graphql/analysis/reducer_state.rb +0 -48
  308. data/lib/graphql/argument.rb +0 -131
  309. data/lib/graphql/authorization.rb +0 -82
  310. data/lib/graphql/backtrace/inspect_result.rb +0 -50
  311. data/lib/graphql/backtrace/legacy_tracer.rb +0 -56
  312. data/lib/graphql/backtrace/tracer.rb +0 -81
  313. data/lib/graphql/backwards_compatibility.rb +0 -61
  314. data/lib/graphql/base_type.rb +0 -232
  315. data/lib/graphql/boolean_type.rb +0 -2
  316. data/lib/graphql/compatibility/execution_specification/counter_schema.rb +0 -53
  317. data/lib/graphql/compatibility/execution_specification/specification_schema.rb +0 -200
  318. data/lib/graphql/compatibility/execution_specification.rb +0 -436
  319. data/lib/graphql/compatibility/lazy_execution_specification/lazy_schema.rb +0 -111
  320. data/lib/graphql/compatibility/lazy_execution_specification.rb +0 -215
  321. data/lib/graphql/compatibility/query_parser_specification/parse_error_specification.rb +0 -87
  322. data/lib/graphql/compatibility/query_parser_specification/query_assertions.rb +0 -79
  323. data/lib/graphql/compatibility/query_parser_specification.rb +0 -266
  324. data/lib/graphql/compatibility/schema_parser_specification.rb +0 -682
  325. data/lib/graphql/compatibility.rb +0 -5
  326. data/lib/graphql/define/assign_argument.rb +0 -12
  327. data/lib/graphql/define/assign_connection.rb +0 -13
  328. data/lib/graphql/define/assign_enum_value.rb +0 -18
  329. data/lib/graphql/define/assign_global_id_field.rb +0 -11
  330. data/lib/graphql/define/assign_mutation_function.rb +0 -34
  331. data/lib/graphql/define/assign_object_field.rb +0 -42
  332. data/lib/graphql/define/defined_object_proxy.rb +0 -53
  333. data/lib/graphql/define/instance_definable.rb +0 -255
  334. data/lib/graphql/define/no_definition_error.rb +0 -7
  335. data/lib/graphql/define/non_null_with_bang.rb +0 -16
  336. data/lib/graphql/define/type_definer.rb +0 -31
  337. data/lib/graphql/define.rb +0 -31
  338. data/lib/graphql/deprecated_dsl.rb +0 -55
  339. data/lib/graphql/deprecation.rb +0 -9
  340. data/lib/graphql/directive/deprecated_directive.rb +0 -2
  341. data/lib/graphql/directive/include_directive.rb +0 -2
  342. data/lib/graphql/directive/skip_directive.rb +0 -2
  343. data/lib/graphql/directive.rb +0 -107
  344. data/lib/graphql/enum_type.rb +0 -133
  345. data/lib/graphql/execution/execute.rb +0 -333
  346. data/lib/graphql/execution/flatten.rb +0 -40
  347. data/lib/graphql/execution/lazy/resolve.rb +0 -91
  348. data/lib/graphql/execution/typecast.rb +0 -50
  349. data/lib/graphql/field/resolve.rb +0 -59
  350. data/lib/graphql/field.rb +0 -226
  351. data/lib/graphql/filter.rb +0 -53
  352. data/lib/graphql/float_type.rb +0 -2
  353. data/lib/graphql/function.rb +0 -128
  354. data/lib/graphql/id_type.rb +0 -2
  355. data/lib/graphql/input_object_type.rb +0 -138
  356. data/lib/graphql/int_type.rb +0 -2
  357. data/lib/graphql/interface_type.rb +0 -72
  358. data/lib/graphql/internal_representation/document.rb +0 -27
  359. data/lib/graphql/internal_representation/node.rb +0 -206
  360. data/lib/graphql/internal_representation/print.rb +0 -51
  361. data/lib/graphql/internal_representation/rewrite.rb +0 -184
  362. data/lib/graphql/internal_representation/scope.rb +0 -88
  363. data/lib/graphql/internal_representation/visit.rb +0 -36
  364. data/lib/graphql/internal_representation.rb +0 -7
  365. data/lib/graphql/language/lexer.rl +0 -260
  366. data/lib/graphql/language/parser.y +0 -550
  367. data/lib/graphql/language/token.rb +0 -34
  368. data/lib/graphql/list_type.rb +0 -80
  369. data/lib/graphql/non_null_type.rb +0 -71
  370. data/lib/graphql/object_type.rb +0 -130
  371. data/lib/graphql/query/arguments.rb +0 -189
  372. data/lib/graphql/query/arguments_cache.rb +0 -24
  373. data/lib/graphql/query/executor.rb +0 -52
  374. data/lib/graphql/query/literal_input.rb +0 -136
  375. data/lib/graphql/query/serial_execution/field_resolution.rb +0 -92
  376. data/lib/graphql/query/serial_execution/operation_resolution.rb +0 -19
  377. data/lib/graphql/query/serial_execution/selection_resolution.rb +0 -23
  378. data/lib/graphql/query/serial_execution/value_resolution.rb +0 -87
  379. data/lib/graphql/query/serial_execution.rb +0 -40
  380. data/lib/graphql/relay/array_connection.rb +0 -83
  381. data/lib/graphql/relay/base_connection.rb +0 -189
  382. data/lib/graphql/relay/connection_instrumentation.rb +0 -54
  383. data/lib/graphql/relay/connection_resolve.rb +0 -43
  384. data/lib/graphql/relay/connection_type.rb +0 -54
  385. data/lib/graphql/relay/edge.rb +0 -27
  386. data/lib/graphql/relay/edge_type.rb +0 -19
  387. data/lib/graphql/relay/edges_instrumentation.rb +0 -39
  388. data/lib/graphql/relay/global_id_resolve.rb +0 -17
  389. data/lib/graphql/relay/mongo_relation_connection.rb +0 -50
  390. data/lib/graphql/relay/mutation/instrumentation.rb +0 -23
  391. data/lib/graphql/relay/mutation/resolve.rb +0 -56
  392. data/lib/graphql/relay/mutation/result.rb +0 -38
  393. data/lib/graphql/relay/mutation.rb +0 -106
  394. data/lib/graphql/relay/node.rb +0 -39
  395. data/lib/graphql/relay/page_info.rb +0 -7
  396. data/lib/graphql/relay/relation_connection.rb +0 -188
  397. data/lib/graphql/relay/type_extensions.rb +0 -32
  398. data/lib/graphql/scalar_type.rb +0 -91
  399. data/lib/graphql/schema/base_64_bp.rb +0 -26
  400. data/lib/graphql/schema/catchall_middleware.rb +0 -35
  401. data/lib/graphql/schema/default_parse_error.rb +0 -10
  402. data/lib/graphql/schema/default_type_error.rb +0 -17
  403. data/lib/graphql/schema/invalid_type_error.rb +0 -7
  404. data/lib/graphql/schema/member/accepts_definition.rb +0 -164
  405. data/lib/graphql/schema/member/cached_graphql_definition.rb +0 -58
  406. data/lib/graphql/schema/member/instrumentation.rb +0 -131
  407. data/lib/graphql/schema/middleware_chain.rb +0 -82
  408. data/lib/graphql/schema/null_mask.rb +0 -11
  409. data/lib/graphql/schema/possible_types.rb +0 -44
  410. data/lib/graphql/schema/rescue_middleware.rb +0 -60
  411. data/lib/graphql/schema/timeout_middleware.rb +0 -88
  412. data/lib/graphql/schema/traversal.rb +0 -228
  413. data/lib/graphql/schema/validation.rb +0 -313
  414. data/lib/graphql/static_validation/default_visitor.rb +0 -15
  415. data/lib/graphql/static_validation/no_validate_visitor.rb +0 -10
  416. data/lib/graphql/static_validation/rules/subscription_root_exists.rb +0 -17
  417. data/lib/graphql/static_validation/type_stack.rb +0 -216
  418. data/lib/graphql/string_type.rb +0 -2
  419. data/lib/graphql/subscriptions/instrumentation.rb +0 -79
  420. data/lib/graphql/subscriptions/subscription_root.rb +0 -76
  421. data/lib/graphql/tracing/skylight_tracing.rb +0 -70
  422. data/lib/graphql/types/relay/default_relay.rb +0 -31
  423. data/lib/graphql/types/relay/node_field.rb +0 -24
  424. data/lib/graphql/types/relay/nodes_field.rb +0 -43
  425. data/lib/graphql/union_type.rb +0 -115
  426. data/lib/graphql/upgrader/member.rb +0 -937
  427. data/lib/graphql/upgrader/schema.rb +0 -38
@@ -3,7 +3,7 @@ module GraphQL
3
3
  module StaticValidation
4
4
  # Default rules for {GraphQL::StaticValidation::Validator}
5
5
  #
6
- # Order is important here. Some validators return {GraphQL::Language::Visitor::SKIP}
6
+ # Order is important here. Some validators skip later hooks.
7
7
  # which stops the visit on that node. That way it doesn't try to find fields on types that
8
8
  # don't exist, etc.
9
9
  ALL_RULES = [
@@ -34,8 +34,9 @@ module GraphQL
34
34
  GraphQL::StaticValidation::VariableUsagesAreAllowed,
35
35
  GraphQL::StaticValidation::MutationRootExists,
36
36
  GraphQL::StaticValidation::QueryRootExists,
37
- GraphQL::StaticValidation::SubscriptionRootExists,
37
+ GraphQL::StaticValidation::SubscriptionRootExistsAndSingleSubscriptionSelection,
38
38
  GraphQL::StaticValidation::InputObjectNamesAreUnique,
39
- ]
39
+ GraphQL::StaticValidation::OneOfInputObjectsAreValid,
40
+ ].freeze
40
41
  end
41
42
  end
@@ -1,7 +1,7 @@
1
1
  # frozen_string_literal: true
2
2
  module GraphQL
3
3
  module StaticValidation
4
- class BaseVisitor < GraphQL::Language::Visitor
4
+ class BaseVisitor < GraphQL::Language::StaticVisitor
5
5
  def initialize(document, context)
6
6
  @path = []
7
7
  @object_types = []
@@ -10,15 +10,11 @@ module GraphQL
10
10
  @argument_definitions = []
11
11
  @directive_definitions = []
12
12
  @context = context
13
+ @types = context.query.types
13
14
  @schema = context.schema
14
15
  super(document)
15
16
  end
16
17
 
17
- # This will be overwritten by {InternalRepresentation::Rewrite} if it's included
18
- def rewrite_document
19
- nil
20
- end
21
-
22
18
  attr_reader :context
23
19
 
24
20
  # @return [Array<GraphQL::ObjectType>] Types whose scope we've entered
@@ -32,22 +28,13 @@ module GraphQL
32
28
  # Build a class to visit the AST and perform validation,
33
29
  # or use a pre-built class if rules is `ALL_RULES` or empty.
34
30
  # @param rules [Array<Module, Class>]
35
- # @param rewrite [Boolean] if `false`, don't include rewrite
36
31
  # @return [Class] A class for validating `rules` during visitation
37
- def self.including_rules(rules, rewrite: true)
32
+ def self.including_rules(rules)
38
33
  if rules.empty?
39
- if rewrite
40
- NoValidateVisitor
41
- else
42
- # It's not doing _anything?!?_
43
- BaseVisitor
44
- end
34
+ # It's not doing _anything?!?_
35
+ BaseVisitor
45
36
  elsif rules == ALL_RULES
46
- if rewrite
47
- DefaultVisitor
48
- else
49
- InterpreterVisitor
50
- end
37
+ InterpreterVisitor
51
38
  else
52
39
  visitor_class = Class.new(self) do
53
40
  include(GraphQL::StaticValidation::DefinitionDependencies)
@@ -60,9 +47,6 @@ module GraphQL
60
47
  end
61
48
  end
62
49
 
63
- if rewrite
64
- visitor_class.include(GraphQL::InternalRepresentation::Rewrite)
65
- end
66
50
  visitor_class.include(ContextMethods)
67
51
  visitor_class
68
52
  end
@@ -94,7 +78,7 @@ module GraphQL
94
78
 
95
79
  def on_field(node, parent)
96
80
  parent_type = @object_types.last
97
- field_definition = @schema.get_field(parent_type, node.name, @context.query.context)
81
+ field_definition = @types.field(parent_type, node.name)
98
82
  @field_definitions.push(field_definition)
99
83
  if !field_definition.nil?
100
84
  next_object_type = field_definition.type.unwrap
@@ -120,14 +104,14 @@ module GraphQL
120
104
  argument_defn = if (arg = @argument_definitions.last)
121
105
  arg_type = arg.type.unwrap
122
106
  if arg_type.kind.input_object?
123
- @context.warden.get_argument(arg_type, node.name)
107
+ @types.argument(arg_type, node.name)
124
108
  else
125
109
  nil
126
110
  end
127
111
  elsif (directive_defn = @directive_definitions.last)
128
- @context.warden.get_argument(directive_defn, node.name)
112
+ @types.argument(directive_defn, node.name)
129
113
  elsif (field_defn = @field_definitions.last)
130
- @context.warden.get_argument(field_defn, node.name)
114
+ @types.argument(field_defn, node.name)
131
115
  else
132
116
  nil
133
117
  end
@@ -187,7 +171,7 @@ module GraphQL
187
171
 
188
172
  def on_fragment_with_type(node)
189
173
  object_type = if node.type
190
- @context.warden.get_type(node.type.name)
174
+ @types.type(node.type.name)
191
175
  else
192
176
  @object_types.last
193
177
  end
@@ -127,8 +127,14 @@ module GraphQL
127
127
  # same name as if they were the same name. If _any_ of the fragments
128
128
  # with that name has a dependency, we record it.
129
129
  independent_fragment_nodes = @defdep_fragment_definitions.values.flatten - @defdep_immediate_dependencies.keys
130
-
130
+ visited_fragment_names = Set.new
131
131
  while fragment_node = independent_fragment_nodes.pop
132
+ if visited_fragment_names.add?(fragment_node.name)
133
+ # this is a new fragment name
134
+ else
135
+ # this is a duplicate fragment name
136
+ next
137
+ end
132
138
  loops += 1
133
139
  if loops > max_loops
134
140
  raise("Resolution loops exceeded the number of definitions; infinite loop detected. (Max: #{max_loops}, Current: #{loops})")
@@ -30,10 +30,10 @@ module GraphQL
30
30
  }.tap { |h| h["path"] = path unless path.nil? }
31
31
  end
32
32
 
33
- private
34
-
35
33
  attr_reader :nodes
36
34
 
35
+ private
36
+
37
37
  def locations
38
38
  nodes.map do |node|
39
39
  h = {"line" => node.line, "column" => node.col}
@@ -5,7 +5,7 @@ module GraphQL
5
5
  class LiteralValidator
6
6
  def initialize(context:)
7
7
  @context = context
8
- @warden = context.warden
8
+ @types = context.types
9
9
  @invalid_response = GraphQL::Query::InputValidationResult.new(valid: false, problems: [])
10
10
  @valid_response = GraphQL::Query::InputValidationResult.new(valid: true, problems: [])
11
11
  end
@@ -18,6 +18,19 @@ module GraphQL
18
18
 
19
19
  private
20
20
 
21
+ def replace_nulls_in(ast_value)
22
+ case ast_value
23
+ when Array
24
+ ast_value.map { |v| replace_nulls_in(v) }
25
+ when GraphQL::Language::Nodes::InputObject
26
+ ast_value.to_h
27
+ when GraphQL::Language::Nodes::NullValue
28
+ nil
29
+ else
30
+ ast_value
31
+ end
32
+ end
33
+
21
34
  def recursively_validate(ast_value, type)
22
35
  if type.nil?
23
36
  # this means we're an undefined argument, see #present_input_field_values_are_valid
@@ -42,7 +55,8 @@ module GraphQL
42
55
  @valid_response
43
56
  elsif type.kind.scalar? && constant_scalar?(ast_value)
44
57
  maybe_raise_if_invalid(ast_value) do
45
- type.validate_input(ast_value, @context)
58
+ ruby_value = replace_nulls_in(ast_value)
59
+ type.validate_input(ruby_value, @context)
46
60
  end
47
61
  elsif type.kind.enum?
48
62
  maybe_raise_if_invalid(ast_value) do
@@ -95,9 +109,9 @@ module GraphQL
95
109
  def required_input_fields_are_present(type, ast_node)
96
110
  # TODO - would be nice to use these to create an error message so the caller knows
97
111
  # that required fields are missing
98
- required_field_names = @warden.arguments(type)
99
- .select { |argument| argument.type.kind.non_null? && @warden.get_argument(type, argument.name) }
100
- .map(&:name)
112
+ required_field_names = @types.arguments(type)
113
+ .select { |argument| argument.type.kind.non_null? && !argument.default_value? }
114
+ .map!(&:name)
101
115
 
102
116
  present_field_names = ast_node.arguments.map(&:name)
103
117
  missing_required_field_names = required_field_names - present_field_names
@@ -105,16 +119,19 @@ module GraphQL
105
119
  missing_required_field_names.empty? ? @valid_response : @invalid_response
106
120
  else
107
121
  results = missing_required_field_names.map do |name|
108
- arg_type = @warden.get_argument(type, name).type
122
+ arg_type = @types.argument(type, name).type
109
123
  recursively_validate(GraphQL::Language::Nodes::NullValue.new(name: name), arg_type)
110
124
  end
125
+ if type.one_of? && ast_node.arguments.size != 1
126
+ results << Query::InputValidationResult.from_problem("`#{type.graphql_name}` is a OneOf type, so only one argument may be given (instead of #{ast_node.arguments.size})")
127
+ end
111
128
  merge_results(results)
112
129
  end
113
130
  end
114
131
 
115
132
  def present_input_field_values_are_valid(type, ast_node)
116
133
  results = ast_node.arguments.map do |value|
117
- field = @warden.get_argument(type, value.name)
134
+ field = @types.argument(type, value.name)
118
135
  # we want to call validate on an argument even if it's an invalid one
119
136
  # so that our raise exception is on it instead of the entire InputObject
120
137
  field_type = field && field.type
@@ -15,7 +15,7 @@ module GraphQL
15
15
  if @context.schema.error_bubbling || context.errors.none? { |err| err.path.take(@path.size) == @path }
16
16
  parent_defn = parent_definition(parent)
17
17
 
18
- if parent_defn && (arg_defn = context.warden.get_argument(parent_defn, node.name))
18
+ if parent_defn && (arg_defn = @types.argument(parent_defn, node.name))
19
19
  validation_result = context.validate_literal(node.value, arg_defn.type)
20
20
  if !validation_result.valid?
21
21
  kind_of_node = node_type(parent)
@@ -16,7 +16,7 @@ module GraphQL
16
16
 
17
17
  def validate_arguments(node)
18
18
  argument_defns = node.arguments
19
- if argument_defns.any?
19
+ if !argument_defns.empty?
20
20
  args_by_name = Hash.new { |h, k| h[k] = [] }
21
21
  argument_defns.each { |a| args_by_name[a.name] << a }
22
22
  args_by_name.each do |name, defns|
@@ -5,13 +5,14 @@ module GraphQL
5
5
  def on_argument(node, parent)
6
6
  parent_defn = parent_definition(parent)
7
7
 
8
- if parent_defn && context.warden.get_argument(parent_defn, node.name)
8
+ if parent_defn && @types.argument(parent_defn, node.name)
9
9
  super
10
10
  elsif parent_defn
11
11
  kind_of_node = node_type(parent)
12
12
  error_arg_name = parent_name(parent, parent_defn)
13
+ arg_names = context.types.arguments(parent_defn).map(&:graphql_name)
13
14
  add_error(GraphQL::StaticValidation::ArgumentsAreDefinedError.new(
14
- "#{kind_of_node} '#{error_arg_name}' doesn't accept argument '#{node.name}'",
15
+ "#{kind_of_node} '#{error_arg_name}' doesn't accept argument '#{node.name}'#{context.did_you_mean_suggestion(node.name, arg_names)}",
15
16
  nodes: node,
16
17
  name: error_arg_name,
17
18
  type: kind_of_node,
@@ -4,16 +4,22 @@ module GraphQL
4
4
  module DirectivesAreDefined
5
5
  def initialize(*)
6
6
  super
7
- @directive_names = context.warden.directives.map(&:graphql_name)
8
7
  end
9
8
 
10
9
  def on_directive(node, parent)
11
- if !@directive_names.include?(node.name)
12
- add_error(GraphQL::StaticValidation::DirectivesAreDefinedError.new(
13
- "Directive @#{node.name} is not defined",
14
- nodes: node,
15
- directive: node.name
16
- ))
10
+ if !@types.directive_exists?(node.name)
11
+ @directives_are_defined_errors_by_name ||= {}
12
+ error = @directives_are_defined_errors_by_name[node.name] ||= begin
13
+ @directive_names ||= @types.directives.map(&:graphql_name)
14
+ err = GraphQL::StaticValidation::DirectivesAreDefinedError.new(
15
+ "Directive @#{node.name} is not defined#{context.did_you_mean_suggestion(node.name, @directive_names)}",
16
+ nodes: [],
17
+ directive: node.name
18
+ )
19
+ add_error(err)
20
+ err
21
+ end
22
+ error.nodes << node
17
23
  else
18
24
  super
19
25
  end
@@ -12,20 +12,22 @@ module GraphQL
12
12
  private
13
13
 
14
14
  LOCATION_MESSAGE_NAMES = {
15
- GraphQL::Directive::QUERY => "queries",
16
- GraphQL::Directive::MUTATION => "mutations",
17
- GraphQL::Directive::SUBSCRIPTION => "subscriptions",
18
- GraphQL::Directive::FIELD => "fields",
19
- GraphQL::Directive::FRAGMENT_DEFINITION => "fragment definitions",
20
- GraphQL::Directive::FRAGMENT_SPREAD => "fragment spreads",
21
- GraphQL::Directive::INLINE_FRAGMENT => "inline fragments",
15
+ GraphQL::Schema::Directive::QUERY => "queries",
16
+ GraphQL::Schema::Directive::MUTATION => "mutations",
17
+ GraphQL::Schema::Directive::SUBSCRIPTION => "subscriptions",
18
+ GraphQL::Schema::Directive::FIELD => "fields",
19
+ GraphQL::Schema::Directive::FRAGMENT_DEFINITION => "fragment definitions",
20
+ GraphQL::Schema::Directive::FRAGMENT_SPREAD => "fragment spreads",
21
+ GraphQL::Schema::Directive::INLINE_FRAGMENT => "inline fragments",
22
+ GraphQL::Schema::Directive::VARIABLE_DEFINITION => "variable definitions",
22
23
  }
23
24
 
24
25
  SIMPLE_LOCATIONS = {
25
- Nodes::Field => GraphQL::Directive::FIELD,
26
- Nodes::InlineFragment => GraphQL::Directive::INLINE_FRAGMENT,
27
- Nodes::FragmentSpread => GraphQL::Directive::FRAGMENT_SPREAD,
28
- Nodes::FragmentDefinition => GraphQL::Directive::FRAGMENT_DEFINITION,
26
+ Nodes::Field => GraphQL::Schema::Directive::FIELD,
27
+ Nodes::InlineFragment => GraphQL::Schema::Directive::INLINE_FRAGMENT,
28
+ Nodes::FragmentSpread => GraphQL::Schema::Directive::FRAGMENT_SPREAD,
29
+ Nodes::FragmentDefinition => GraphQL::Schema::Directive::FRAGMENT_DEFINITION,
30
+ Nodes::VariableDefinition => GraphQL::Schema::Directive::VARIABLE_DEFINITION,
29
31
  }
30
32
 
31
33
  SIMPLE_LOCATION_NODES = SIMPLE_LOCATIONS.keys
@@ -34,7 +36,7 @@ module GraphQL
34
36
  directive_defn = directives[ast_directive.name]
35
37
  case ast_parent
36
38
  when Nodes::OperationDefinition
37
- required_location = GraphQL::Directive.const_get(ast_parent.operation_type.upcase)
39
+ required_location = GraphQL::Schema::Directive.const_get(ast_parent.operation_type.upcase)
38
40
  assert_includes_location(directive_defn, ast_directive, required_location)
39
41
  when *SIMPLE_LOCATION_NODES
40
42
  required_location = SIMPLE_LOCATIONS[ast_parent.class]
@@ -4,7 +4,7 @@ module GraphQL
4
4
  module FieldsAreDefinedOnType
5
5
  def on_field(node, parent)
6
6
  parent_type = @object_types[-2]
7
- field = context.warden.get_field(parent_type, node.name)
7
+ field = context.query.types.field(parent_type, node.name)
8
8
 
9
9
  if field.nil?
10
10
  if parent_type.kind.union?
@@ -14,8 +14,11 @@ module GraphQL
14
14
  node_name: parent_type.graphql_name
15
15
  ))
16
16
  else
17
+ possible_fields = possible_fields(context, parent_type)
18
+ suggestion = context.did_you_mean_suggestion(node.name, possible_fields)
19
+ message = "Field '#{node.name}' doesn't exist on type '#{parent_type.graphql_name}'#{suggestion}"
17
20
  add_error(GraphQL::StaticValidation::FieldsAreDefinedOnTypeError.new(
18
- "Field '#{node.name}' doesn't exist on type '#{parent_type.graphql_name}'",
21
+ message,
19
22
  nodes: node,
20
23
  field: node.name,
21
24
  type: parent_type.graphql_name
@@ -25,6 +28,13 @@ module GraphQL
25
28
  super
26
29
  end
27
30
  end
31
+
32
+ private
33
+
34
+ def possible_fields(context, parent_type)
35
+ return EmptyObjects::EMPTY_ARRAY if parent_type.kind.leaf?
36
+ context.types.fields(parent_type).map(&:graphql_name)
37
+ end
28
38
  end
29
39
  end
30
40
  end
@@ -25,14 +25,56 @@ module GraphQL
25
25
  def validate_field_selections(ast_node, resolved_type)
26
26
  msg = if resolved_type.nil?
27
27
  nil
28
- elsif resolved_type.kind.scalar? && ast_node.selections.any?
29
- if ast_node.selections.first.is_a?(GraphQL::Language::Nodes::InlineFragment)
30
- "Selections can't be made on scalars (%{node_name} returns #{resolved_type.graphql_name} but has inline fragments [#{ast_node.selections.map(&:type).map(&:name).join(", ")}])"
28
+ elsif resolved_type.kind.leaf?
29
+ if !ast_node.selections.empty?
30
+ selection_strs = ast_node.selections.map do |n|
31
+ case n
32
+ when GraphQL::Language::Nodes::InlineFragment
33
+ "\"... on #{n.type.name} { ... }\""
34
+ when GraphQL::Language::Nodes::Field
35
+ "\"#{n.name}\""
36
+ when GraphQL::Language::Nodes::FragmentSpread
37
+ "\"#{n.name}\""
38
+ else
39
+ raise "Invariant: unexpected selection node: #{n}"
40
+ end
41
+ end
42
+ "Selections can't be made on #{resolved_type.kind.name.sub("_", " ").downcase}s (%{node_name} returns #{resolved_type.graphql_name} but has selections [#{selection_strs.join(", ")}])"
43
+ else
44
+ nil
45
+ end
46
+ elsif ast_node.selections.empty?
47
+ return_validation_error = true
48
+ legacy_invalid_empty_selection_result = nil
49
+ if !resolved_type.kind.fields?
50
+ case @schema.allow_legacy_invalid_empty_selections_on_union
51
+ when true
52
+ legacy_invalid_empty_selection_result = @schema.legacy_invalid_empty_selections_on_union(@context.query)
53
+ case legacy_invalid_empty_selection_result
54
+ when :return_validation_error
55
+ # keep `return_validation_error = true`
56
+ when String
57
+ return_validation_error = false
58
+ # the string is returned below
59
+ when nil
60
+ # No error:
61
+ return_validation_error = false
62
+ legacy_invalid_empty_selection_result = nil
63
+ else
64
+ raise GraphQL::InvariantError, "Unexpected return value from legacy_invalid_empty_selections_on_union, must be `:return_validation_error`, String, or nil (got: #{legacy_invalid_empty_selection_result.inspect})"
65
+ end
66
+ when false
67
+ # pass -- error below
68
+ else
69
+ return_validation_error = false
70
+ @context.query.logger.warn("Unions require selections but #{ast_node.alias || ast_node.name} (#{resolved_type.graphql_name}) doesn't have any. This will fail with a validation error on a future GraphQL-Ruby version. More info: https://graphql-ruby.org/api-doc/#{GraphQL::VERSION}/GraphQL/Schema.html#allow_legacy_invalid_empty_selections_on_union-class_method")
71
+ end
72
+ end
73
+ if return_validation_error
74
+ "Field must have selections (%{node_name} returns #{resolved_type.graphql_name} but has no selections. Did you mean '#{ast_node.name} { ... }'?)"
31
75
  else
32
- "Selections can't be made on scalars (%{node_name} returns #{resolved_type.graphql_name} but has selections [#{ast_node.selections.map(&:name).join(", ")}])"
76
+ legacy_invalid_empty_selection_result
33
77
  end
34
- elsif resolved_type.kind.fields? && ast_node.selections.empty?
35
- "Field must have selections (%{node_name} returns #{resolved_type.graphql_name} but has no selections. Did you mean '#{ast_node.name} { ... }'?)"
36
78
  else
37
79
  nil
38
80
  end
@@ -9,7 +9,7 @@ module GraphQL
9
9
  # without ambiguity.
10
10
  #
11
11
  # Original Algorithm: https://github.com/graphql/graphql-js/blob/master/src/validation/rules/OverlappingFieldsCanBeMerged.js
12
- NO_ARGS = {}.freeze
12
+ NO_ARGS = GraphQL::EmptyObjects::EMPTY_HASH
13
13
 
14
14
  Field = Struct.new(:node, :definition, :owner_type, :parents)
15
15
  FragmentSpread = Struct.new(:name, :parents)
@@ -33,26 +33,19 @@ module GraphQL
33
33
 
34
34
  private
35
35
 
36
- def field_conflicts
37
- @field_conflicts ||= Hash.new do |errors, field|
38
- errors[field] = GraphQL::StaticValidation::FieldsWillMergeError.new(kind: :field, field_name: field)
39
- end
40
- end
41
-
42
- def arg_conflicts
43
- @arg_conflicts ||= Hash.new do |errors, field|
44
- errors[field] = GraphQL::StaticValidation::FieldsWillMergeError.new(kind: :argument, field_name: field)
36
+ def conflicts
37
+ @conflicts ||= Hash.new do |h, error_type|
38
+ h[error_type] = Hash.new do |h2, field_name|
39
+ h2[field_name] = GraphQL::StaticValidation::FieldsWillMergeError.new(kind: error_type, field_name: field_name)
40
+ end
45
41
  end
46
42
  end
47
43
 
48
44
  def setting_errors
49
- @field_conflicts = nil
50
- @arg_conflicts = nil
51
-
45
+ @conflicts = nil
52
46
  yield
53
47
  # don't initialize these if they weren't initialized in the block:
54
- @field_conflicts && @field_conflicts.each_value { |error| add_error(error) }
55
- @arg_conflicts && @arg_conflicts.each_value { |error| add_error(error) }
48
+ @conflicts&.each_value { |error_type| error_type.each_value { |error| add_error(error) } }
56
49
  end
57
50
 
58
51
  def conflicts_within_selection_set(node, parent_type)
@@ -117,8 +110,8 @@ module GraphQL
117
110
 
118
111
  return if fragment1.nil? || fragment2.nil?
119
112
 
120
- fragment_type1 = context.warden.get_type(fragment1.type.name)
121
- fragment_type2 = context.warden.get_type(fragment2.type.name)
113
+ fragment_type1 = context.query.types.type(fragment1.type.name)
114
+ fragment_type2 = context.query.types.type(fragment2.type.name)
122
115
 
123
116
  return if fragment_type1.nil? || fragment_type2.nil?
124
117
 
@@ -170,7 +163,7 @@ module GraphQL
170
163
  fragment = context.fragments[fragment_name]
171
164
  return if fragment.nil?
172
165
 
173
- fragment_type = context.warden.get_type(fragment.type.name)
166
+ fragment_type = @types.type(fragment.type.name)
174
167
  return if fragment_type.nil?
175
168
 
176
169
  fragment_fields, fragment_spreads = fields_and_fragments_from_selection(fragment, owner_type: fragment_type, parents: [*fragment_spread.parents, fragment_type])
@@ -212,6 +205,7 @@ module GraphQL
212
205
 
213
206
  def find_conflict(response_key, field1, field2, mutually_exclusive: false)
214
207
  return if @conflict_count >= context.max_errors
208
+ return if field1.definition.nil? || field2.definition.nil?
215
209
 
216
210
  node1 = field1.node
217
211
  node2 = field2.node
@@ -221,7 +215,7 @@ module GraphQL
221
215
 
222
216
  if !are_mutually_exclusive
223
217
  if node1.name != node2.name
224
- conflict = field_conflicts[response_key]
218
+ conflict = conflicts[:field][response_key]
225
219
 
226
220
  conflict.add_conflict(node1, node1.name)
227
221
  conflict.add_conflict(node2, node2.name)
@@ -230,7 +224,7 @@ module GraphQL
230
224
  end
231
225
 
232
226
  if !same_arguments?(node1, node2)
233
- conflict = arg_conflicts[response_key]
227
+ conflict = conflicts[:argument][response_key]
234
228
 
235
229
  conflict.add_conflict(node1, GraphQL::Language.serialize(serialize_field_args(node1)))
236
230
  conflict.add_conflict(node2, GraphQL::Language.serialize(serialize_field_args(node2)))
@@ -239,6 +233,49 @@ module GraphQL
239
233
  end
240
234
  end
241
235
 
236
+ if !conflicts[:field].key?(response_key) &&
237
+ (t1 = field1.definition&.type) &&
238
+ (t2 = field2.definition&.type) &&
239
+ return_types_conflict?(t1, t2)
240
+
241
+ return_error = nil
242
+ message_override = nil
243
+ case @schema.allow_legacy_invalid_return_type_conflicts
244
+ when false
245
+ return_error = true
246
+ when true
247
+ legacy_handling = @schema.legacy_invalid_return_type_conflicts(@context.query, t1, t2, node1, node2)
248
+ case legacy_handling
249
+ when nil
250
+ return_error = false
251
+ when :return_validation_error
252
+ return_error = true
253
+ when String
254
+ return_error = true
255
+ message_override = legacy_handling
256
+ else
257
+ raise GraphQL::Error, "#{@schema}.legacy_invalid_scalar_conflicts returned unexpected value: #{legacy_handling.inspect}. Expected `nil`, String, or `:return_validation_error`."
258
+ end
259
+ else
260
+ return_error = false
261
+ @context.query.logger.warn <<~WARN
262
+ GraphQL-Ruby encountered mismatched types in this query: `#{t1.to_type_signature}` (at #{node1.line}:#{node1.col}) vs. `#{t2.to_type_signature}` (at #{node2.line}:#{node2.col}).
263
+ This will return an error in future GraphQL-Ruby versions, as per the GraphQL specification
264
+ Learn about migrating here: https://graphql-ruby.org/api-doc/#{GraphQL::VERSION}/GraphQL/Schema.html#allow_legacy_invalid_return_type_conflicts-class_method
265
+ WARN
266
+ end
267
+
268
+ if return_error
269
+ conflict = conflicts[:return_type][response_key]
270
+ if message_override
271
+ conflict.message = message_override
272
+ end
273
+ conflict.add_conflict(node1, "`#{t1.to_type_signature}`")
274
+ conflict.add_conflict(node2, "`#{t2.to_type_signature}`")
275
+ @conflict_count += 1
276
+ end
277
+ end
278
+
242
279
  find_conflicts_between_sub_selection_sets(
243
280
  field1,
244
281
  field2,
@@ -246,6 +283,32 @@ module GraphQL
246
283
  )
247
284
  end
248
285
 
286
+ def return_types_conflict?(type1, type2)
287
+ if type1.list?
288
+ if type2.list?
289
+ return_types_conflict?(type1.of_type, type2.of_type)
290
+ else
291
+ true
292
+ end
293
+ elsif type2.list?
294
+ true
295
+ elsif type1.non_null?
296
+ if type2.non_null?
297
+ return_types_conflict?(type1.of_type, type2.of_type)
298
+ else
299
+ true
300
+ end
301
+ elsif type2.non_null?
302
+ true
303
+ elsif type1.kind.leaf? && type2.kind.leaf?
304
+ type1 != type2
305
+ else
306
+ # One or more of these are composite types,
307
+ # their selections will be validated later on.
308
+ false
309
+ end
310
+ end
311
+
249
312
  def find_conflicts_between_sub_selection_sets(field1, field2, mutually_exclusive:)
250
313
  return if field1.definition.nil? ||
251
314
  field2.definition.nil? ||
@@ -323,7 +386,7 @@ module GraphQL
323
386
  end
324
387
  end
325
388
 
326
- NO_SELECTIONS = [{}.freeze, [].freeze].freeze
389
+ NO_SELECTIONS = [GraphQL::EmptyObjects::EMPTY_HASH, GraphQL::EmptyObjects::EMPTY_ARRAY].freeze
327
390
 
328
391
  def fields_and_fragments_from_selection(node, owner_type:, parents:)
329
392
  if node.selections.empty?
@@ -340,11 +403,11 @@ module GraphQL
340
403
  selections.each do |node|
341
404
  case node
342
405
  when GraphQL::Language::Nodes::Field
343
- definition = context.query.get_field(owner_type, node.name)
406
+ definition = @types.field(owner_type, node.name)
344
407
  fields << Field.new(node, definition, owner_type, parents)
345
408
  when GraphQL::Language::Nodes::InlineFragment
346
- fragment_type = node.type ? context.warden.get_type(node.type.name) : owner_type
347
- find_fields_and_fragments(node.selections, parents: [*parents, fragment_type], owner_type: owner_type, fields: fields, fragment_spreads: fragment_spreads) if fragment_type
409
+ fragment_type = node.type ? @types.type(node.type.name) : owner_type
410
+ find_fields_and_fragments(node.selections, parents: [*parents, fragment_type], owner_type: fragment_type, fields: fields, fragment_spreads: fragment_spreads) if fragment_type
348
411
  when GraphQL::Language::Nodes::FragmentSpread
349
412
  fragment_spreads << FragmentSpread.new(node.name, parents)
350
413
  end
@@ -396,7 +459,7 @@ module GraphQL
396
459
  end
397
460
 
398
461
  # Given two list of parents, find out if they are mutually exclusive
399
- # In this context, `parents` represends the "self scope" of the field,
462
+ # In this context, `parents` represents the "self scope" of the field,
400
463
  # what types may be found at this point in the query.
401
464
  def mutually_exclusive?(parents1, parents2)
402
465
  if parents1.empty? || parents2.empty?
@@ -411,8 +474,8 @@ module GraphQL
411
474
  false
412
475
  else
413
476
  # Check if these two scopes have _any_ types in common.
414
- possible_right_types = context.query.possible_types(type1)
415
- possible_left_types = context.query.possible_types(type2)
477
+ possible_right_types = context.types.possible_types(type1)
478
+ possible_left_types = context.types.possible_types(type2)
416
479
  (possible_right_types & possible_left_types).empty?
417
480
  end
418
481
  end