graphql 1.10.1 → 1.13.0

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

Potentially problematic release.


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

Files changed (292) hide show
  1. checksums.yaml +4 -4
  2. data/lib/generators/graphql/core.rb +18 -2
  3. data/lib/generators/graphql/install_generator.rb +36 -6
  4. data/lib/generators/graphql/loader_generator.rb +1 -0
  5. data/lib/generators/graphql/mutation_generator.rb +2 -1
  6. data/lib/generators/graphql/object_generator.rb +54 -9
  7. data/lib/generators/graphql/relay.rb +63 -0
  8. data/lib/generators/graphql/relay_generator.rb +21 -0
  9. data/lib/generators/graphql/templates/base_argument.erb +2 -0
  10. data/lib/generators/graphql/templates/base_connection.erb +8 -0
  11. data/lib/generators/graphql/templates/base_edge.erb +8 -0
  12. data/lib/generators/graphql/templates/base_enum.erb +2 -0
  13. data/lib/generators/graphql/templates/base_field.erb +2 -0
  14. data/lib/generators/graphql/templates/base_input_object.erb +2 -0
  15. data/lib/generators/graphql/templates/base_interface.erb +2 -0
  16. data/lib/generators/graphql/templates/base_mutation.erb +2 -0
  17. data/lib/generators/graphql/templates/base_object.erb +2 -0
  18. data/lib/generators/graphql/templates/base_scalar.erb +2 -0
  19. data/lib/generators/graphql/templates/base_union.erb +2 -0
  20. data/lib/generators/graphql/templates/enum.erb +2 -0
  21. data/lib/generators/graphql/templates/graphql_controller.erb +16 -12
  22. data/lib/generators/graphql/templates/interface.erb +2 -0
  23. data/lib/generators/graphql/templates/loader.erb +2 -0
  24. data/lib/generators/graphql/templates/mutation.erb +2 -0
  25. data/lib/generators/graphql/templates/mutation_type.erb +2 -0
  26. data/lib/generators/graphql/templates/node_type.erb +9 -0
  27. data/lib/generators/graphql/templates/object.erb +3 -1
  28. data/lib/generators/graphql/templates/query_type.erb +3 -3
  29. data/lib/generators/graphql/templates/scalar.erb +2 -0
  30. data/lib/generators/graphql/templates/schema.erb +21 -33
  31. data/lib/generators/graphql/templates/union.erb +3 -1
  32. data/lib/generators/graphql/type_generator.rb +1 -1
  33. data/lib/graphql/analysis/analyze_query.rb +7 -0
  34. data/lib/graphql/analysis/ast/field_usage.rb +24 -1
  35. data/lib/graphql/analysis/ast/query_complexity.rb +126 -109
  36. data/lib/graphql/analysis/ast/visitor.rb +13 -5
  37. data/lib/graphql/analysis/ast.rb +11 -2
  38. data/lib/graphql/argument.rb +3 -3
  39. data/lib/graphql/backtrace/inspect_result.rb +0 -1
  40. data/lib/graphql/backtrace/legacy_tracer.rb +56 -0
  41. data/lib/graphql/backtrace/table.rb +34 -3
  42. data/lib/graphql/backtrace/traced_error.rb +0 -1
  43. data/lib/graphql/backtrace/tracer.rb +40 -9
  44. data/lib/graphql/backtrace.rb +28 -19
  45. data/lib/graphql/backwards_compatibility.rb +2 -1
  46. data/lib/graphql/base_type.rb +1 -1
  47. data/lib/graphql/compatibility/execution_specification/specification_schema.rb +2 -2
  48. data/lib/graphql/compatibility/execution_specification.rb +1 -0
  49. data/lib/graphql/compatibility/lazy_execution_specification.rb +2 -0
  50. data/lib/graphql/compatibility/query_parser_specification.rb +2 -0
  51. data/lib/graphql/compatibility/schema_parser_specification.rb +2 -0
  52. data/lib/graphql/dataloader/null_dataloader.rb +22 -0
  53. data/lib/graphql/dataloader/request.rb +19 -0
  54. data/lib/graphql/dataloader/request_all.rb +19 -0
  55. data/lib/graphql/dataloader/source.rb +155 -0
  56. data/lib/graphql/dataloader.rb +308 -0
  57. data/lib/graphql/define/assign_global_id_field.rb +2 -2
  58. data/lib/graphql/define/defined_object_proxy.rb +1 -1
  59. data/lib/graphql/define/instance_definable.rb +34 -4
  60. data/lib/graphql/define/type_definer.rb +5 -5
  61. data/lib/graphql/deprecated_dsl.rb +18 -5
  62. data/lib/graphql/deprecation.rb +9 -0
  63. data/lib/graphql/directive.rb +4 -4
  64. data/lib/graphql/enum_type.rb +7 -1
  65. data/lib/graphql/execution/errors.rb +110 -7
  66. data/lib/graphql/execution/execute.rb +8 -1
  67. data/lib/graphql/execution/instrumentation.rb +1 -1
  68. data/lib/graphql/execution/interpreter/argument_value.rb +28 -0
  69. data/lib/graphql/execution/interpreter/arguments.rb +88 -0
  70. data/lib/graphql/execution/interpreter/arguments_cache.rb +103 -0
  71. data/lib/graphql/execution/interpreter/handles_raw_value.rb +18 -0
  72. data/lib/graphql/execution/interpreter/resolve.rb +37 -25
  73. data/lib/graphql/execution/interpreter/runtime.rb +685 -421
  74. data/lib/graphql/execution/interpreter.rb +42 -13
  75. data/lib/graphql/execution/lazy.rb +5 -1
  76. data/lib/graphql/execution/lookahead.rb +25 -110
  77. data/lib/graphql/execution/multiplex.rb +37 -25
  78. data/lib/graphql/field.rb +5 -1
  79. data/lib/graphql/function.rb +4 -0
  80. data/lib/graphql/input_object_type.rb +6 -0
  81. data/lib/graphql/integer_decoding_error.rb +17 -0
  82. data/lib/graphql/integer_encoding_error.rb +18 -2
  83. data/lib/graphql/interface_type.rb +7 -0
  84. data/lib/graphql/internal_representation/document.rb +2 -2
  85. data/lib/graphql/internal_representation/rewrite.rb +1 -1
  86. data/lib/graphql/internal_representation/scope.rb +2 -2
  87. data/lib/graphql/internal_representation/visit.rb +2 -2
  88. data/lib/graphql/introspection/directive_type.rb +8 -4
  89. data/lib/graphql/introspection/entry_points.rb +2 -2
  90. data/lib/graphql/introspection/enum_value_type.rb +2 -2
  91. data/lib/graphql/introspection/field_type.rb +9 -5
  92. data/lib/graphql/introspection/input_value_type.rb +15 -3
  93. data/lib/graphql/introspection/introspection_query.rb +6 -92
  94. data/lib/graphql/introspection/schema_type.rb +4 -4
  95. data/lib/graphql/introspection/type_type.rb +16 -12
  96. data/lib/graphql/introspection.rb +96 -0
  97. data/lib/graphql/invalid_null_error.rb +18 -0
  98. data/lib/graphql/language/block_string.rb +20 -5
  99. data/lib/graphql/language/cache.rb +37 -0
  100. data/lib/graphql/language/document_from_schema_definition.rb +73 -25
  101. data/lib/graphql/language/lexer.rb +4 -3
  102. data/lib/graphql/language/lexer.rl +3 -3
  103. data/lib/graphql/language/nodes.rb +51 -89
  104. data/lib/graphql/language/parser.rb +552 -530
  105. data/lib/graphql/language/parser.y +114 -99
  106. data/lib/graphql/language/printer.rb +7 -2
  107. data/lib/graphql/language/sanitized_printer.rb +222 -0
  108. data/lib/graphql/language/token.rb +0 -4
  109. data/lib/graphql/language/visitor.rb +2 -2
  110. data/lib/graphql/language.rb +2 -0
  111. data/lib/graphql/name_validator.rb +2 -7
  112. data/lib/graphql/object_type.rb +44 -35
  113. data/lib/graphql/pagination/active_record_relation_connection.rb +14 -1
  114. data/lib/graphql/pagination/array_connection.rb +2 -2
  115. data/lib/graphql/pagination/connection.rb +75 -20
  116. data/lib/graphql/pagination/connections.rb +83 -31
  117. data/lib/graphql/pagination/relation_connection.rb +34 -14
  118. data/lib/graphql/parse_error.rb +0 -1
  119. data/lib/graphql/query/arguments.rb +4 -3
  120. data/lib/graphql/query/arguments_cache.rb +1 -2
  121. data/lib/graphql/query/context.rb +42 -7
  122. data/lib/graphql/query/executor.rb +0 -1
  123. data/lib/graphql/query/fingerprint.rb +26 -0
  124. data/lib/graphql/query/input_validation_result.rb +23 -6
  125. data/lib/graphql/query/literal_input.rb +1 -1
  126. data/lib/graphql/query/null_context.rb +24 -8
  127. data/lib/graphql/query/serial_execution/field_resolution.rb +1 -1
  128. data/lib/graphql/query/serial_execution.rb +1 -0
  129. data/lib/graphql/query/validation_pipeline.rb +5 -2
  130. data/lib/graphql/query/variable_validation_error.rb +1 -1
  131. data/lib/graphql/query/variables.rb +14 -4
  132. data/lib/graphql/query.rb +68 -13
  133. data/lib/graphql/railtie.rb +9 -1
  134. data/lib/graphql/rake_task.rb +12 -9
  135. data/lib/graphql/relay/array_connection.rb +10 -12
  136. data/lib/graphql/relay/base_connection.rb +26 -13
  137. data/lib/graphql/relay/connection_instrumentation.rb +4 -4
  138. data/lib/graphql/relay/connection_type.rb +1 -1
  139. data/lib/graphql/relay/edges_instrumentation.rb +0 -1
  140. data/lib/graphql/relay/mutation.rb +1 -0
  141. data/lib/graphql/relay/node.rb +3 -0
  142. data/lib/graphql/relay/range_add.rb +23 -9
  143. data/lib/graphql/relay/relation_connection.rb +8 -10
  144. data/lib/graphql/relay/type_extensions.rb +2 -0
  145. data/lib/graphql/rubocop/graphql/base_cop.rb +36 -0
  146. data/lib/graphql/rubocop/graphql/default_null_true.rb +43 -0
  147. data/lib/graphql/rubocop/graphql/default_required_true.rb +43 -0
  148. data/lib/graphql/rubocop.rb +4 -0
  149. data/lib/graphql/scalar_type.rb +16 -1
  150. data/lib/graphql/schema/addition.rb +247 -0
  151. data/lib/graphql/schema/argument.rb +210 -12
  152. data/lib/graphql/schema/base_64_encoder.rb +2 -0
  153. data/lib/graphql/schema/build_from_definition/resolve_map.rb +3 -1
  154. data/lib/graphql/schema/build_from_definition.rb +213 -86
  155. data/lib/graphql/schema/default_type_error.rb +2 -0
  156. data/lib/graphql/schema/directive/deprecated.rb +1 -1
  157. data/lib/graphql/schema/directive/feature.rb +1 -1
  158. data/lib/graphql/schema/directive/flagged.rb +57 -0
  159. data/lib/graphql/schema/directive/include.rb +1 -1
  160. data/lib/graphql/schema/directive/skip.rb +1 -1
  161. data/lib/graphql/schema/directive/transform.rb +14 -2
  162. data/lib/graphql/schema/directive.rb +78 -2
  163. data/lib/graphql/schema/enum.rb +80 -9
  164. data/lib/graphql/schema/enum_value.rb +17 -6
  165. data/lib/graphql/schema/field/connection_extension.rb +46 -30
  166. data/lib/graphql/schema/field/scope_extension.rb +1 -1
  167. data/lib/graphql/schema/field.rb +285 -133
  168. data/lib/graphql/schema/find_inherited_value.rb +4 -1
  169. data/lib/graphql/schema/finder.rb +5 -5
  170. data/lib/graphql/schema/input_object.rb +97 -89
  171. data/lib/graphql/schema/interface.rb +24 -19
  172. data/lib/graphql/schema/late_bound_type.rb +2 -2
  173. data/lib/graphql/schema/list.rb +7 -1
  174. data/lib/graphql/schema/loader.rb +137 -103
  175. data/lib/graphql/schema/member/accepts_definition.rb +8 -1
  176. data/lib/graphql/schema/member/base_dsl_methods.rb +15 -19
  177. data/lib/graphql/schema/member/build_type.rb +14 -7
  178. data/lib/graphql/schema/member/has_arguments.rb +205 -12
  179. data/lib/graphql/schema/member/has_ast_node.rb +4 -1
  180. data/lib/graphql/schema/member/has_deprecation_reason.rb +25 -0
  181. data/lib/graphql/schema/member/has_directives.rb +98 -0
  182. data/lib/graphql/schema/member/has_fields.rb +95 -30
  183. data/lib/graphql/schema/member/has_interfaces.rb +90 -0
  184. data/lib/graphql/schema/member/has_unresolved_type_error.rb +15 -0
  185. data/lib/graphql/schema/member/has_validators.rb +31 -0
  186. data/lib/graphql/schema/member/instrumentation.rb +0 -1
  187. data/lib/graphql/schema/member/type_system_helpers.rb +3 -3
  188. data/lib/graphql/schema/member.rb +6 -0
  189. data/lib/graphql/schema/middleware_chain.rb +1 -1
  190. data/lib/graphql/schema/mutation.rb +4 -0
  191. data/lib/graphql/schema/non_null.rb +5 -0
  192. data/lib/graphql/schema/object.rb +47 -46
  193. data/lib/graphql/schema/possible_types.rb +9 -4
  194. data/lib/graphql/schema/printer.rb +16 -34
  195. data/lib/graphql/schema/relay_classic_mutation.rb +32 -4
  196. data/lib/graphql/schema/resolver/has_payload_type.rb +34 -4
  197. data/lib/graphql/schema/resolver.rb +123 -63
  198. data/lib/graphql/schema/scalar.rb +11 -1
  199. data/lib/graphql/schema/subscription.rb +57 -21
  200. data/lib/graphql/schema/timeout.rb +29 -15
  201. data/lib/graphql/schema/timeout_middleware.rb +3 -1
  202. data/lib/graphql/schema/type_expression.rb +1 -1
  203. data/lib/graphql/schema/type_membership.rb +18 -4
  204. data/lib/graphql/schema/union.rb +41 -1
  205. data/lib/graphql/schema/unique_within_type.rb +1 -2
  206. data/lib/graphql/schema/validation.rb +12 -2
  207. data/lib/graphql/schema/validator/allow_blank_validator.rb +29 -0
  208. data/lib/graphql/schema/validator/allow_null_validator.rb +26 -0
  209. data/lib/graphql/schema/validator/exclusion_validator.rb +33 -0
  210. data/lib/graphql/schema/validator/format_validator.rb +48 -0
  211. data/lib/graphql/schema/validator/inclusion_validator.rb +35 -0
  212. data/lib/graphql/schema/validator/length_validator.rb +59 -0
  213. data/lib/graphql/schema/validator/numericality_validator.rb +82 -0
  214. data/lib/graphql/schema/validator/required_validator.rb +68 -0
  215. data/lib/graphql/schema/validator.rb +174 -0
  216. data/lib/graphql/schema/warden.rb +153 -28
  217. data/lib/graphql/schema.rb +364 -330
  218. data/lib/graphql/static_validation/all_rules.rb +1 -0
  219. data/lib/graphql/static_validation/base_visitor.rb +8 -5
  220. data/lib/graphql/static_validation/definition_dependencies.rb +0 -1
  221. data/lib/graphql/static_validation/error.rb +3 -1
  222. data/lib/graphql/static_validation/literal_validator.rb +51 -26
  223. data/lib/graphql/static_validation/rules/argument_literals_are_compatible.rb +44 -87
  224. data/lib/graphql/static_validation/rules/argument_literals_are_compatible_error.rb +22 -6
  225. data/lib/graphql/static_validation/rules/arguments_are_defined.rb +28 -22
  226. data/lib/graphql/static_validation/rules/arguments_are_defined_error.rb +4 -2
  227. data/lib/graphql/static_validation/rules/directives_are_defined.rb +1 -1
  228. data/lib/graphql/static_validation/rules/fields_will_merge.rb +79 -43
  229. data/lib/graphql/static_validation/rules/fields_will_merge_error.rb +25 -4
  230. data/lib/graphql/static_validation/rules/fragments_are_finite.rb +2 -2
  231. data/lib/graphql/static_validation/rules/input_object_names_are_unique.rb +30 -0
  232. data/lib/graphql/static_validation/rules/input_object_names_are_unique_error.rb +30 -0
  233. data/lib/graphql/static_validation/rules/required_arguments_are_present.rb +1 -1
  234. data/lib/graphql/static_validation/rules/required_input_object_attributes_are_present.rb +6 -7
  235. data/lib/graphql/static_validation/rules/variable_default_values_are_correctly_typed.rb +9 -10
  236. data/lib/graphql/static_validation/rules/variable_usages_are_allowed.rb +8 -8
  237. data/lib/graphql/static_validation/rules/variables_are_used_and_defined.rb +4 -2
  238. data/lib/graphql/static_validation/validation_context.rb +9 -3
  239. data/lib/graphql/static_validation/validation_timeout_error.rb +25 -0
  240. data/lib/graphql/static_validation/validator.rb +42 -8
  241. data/lib/graphql/static_validation.rb +1 -0
  242. data/lib/graphql/string_encoding_error.rb +13 -3
  243. data/lib/graphql/subscriptions/action_cable_subscriptions.rb +118 -19
  244. data/lib/graphql/subscriptions/broadcast_analyzer.rb +81 -0
  245. data/lib/graphql/subscriptions/default_subscription_resolve_extension.rb +21 -0
  246. data/lib/graphql/subscriptions/event.rb +81 -30
  247. data/lib/graphql/subscriptions/instrumentation.rb +0 -1
  248. data/lib/graphql/subscriptions/serialize.rb +33 -6
  249. data/lib/graphql/subscriptions/subscription_root.rb +15 -4
  250. data/lib/graphql/subscriptions.rb +88 -45
  251. data/lib/graphql/tracing/active_support_notifications_tracing.rb +2 -1
  252. data/lib/graphql/tracing/appoptics_tracing.rb +173 -0
  253. data/lib/graphql/tracing/appsignal_tracing.rb +15 -0
  254. data/lib/graphql/tracing/new_relic_tracing.rb +1 -12
  255. data/lib/graphql/tracing/platform_tracing.rb +43 -17
  256. data/lib/graphql/tracing/prometheus_tracing/graphql_collector.rb +4 -1
  257. data/lib/graphql/tracing/scout_tracing.rb +11 -0
  258. data/lib/graphql/tracing/skylight_tracing.rb +1 -1
  259. data/lib/graphql/tracing/statsd_tracing.rb +42 -0
  260. data/lib/graphql/tracing.rb +9 -33
  261. data/lib/graphql/types/big_int.rb +5 -1
  262. data/lib/graphql/types/int.rb +10 -3
  263. data/lib/graphql/types/iso_8601_date.rb +3 -3
  264. data/lib/graphql/types/iso_8601_date_time.rb +25 -10
  265. data/lib/graphql/types/relay/base_connection.rb +6 -90
  266. data/lib/graphql/types/relay/base_edge.rb +2 -34
  267. data/lib/graphql/types/relay/connection_behaviors.rb +156 -0
  268. data/lib/graphql/types/relay/default_relay.rb +27 -0
  269. data/lib/graphql/types/relay/edge_behaviors.rb +53 -0
  270. data/lib/graphql/types/relay/has_node_field.rb +41 -0
  271. data/lib/graphql/types/relay/has_nodes_field.rb +41 -0
  272. data/lib/graphql/types/relay/node.rb +2 -4
  273. data/lib/graphql/types/relay/node_behaviors.rb +15 -0
  274. data/lib/graphql/types/relay/node_field.rb +2 -20
  275. data/lib/graphql/types/relay/nodes_field.rb +2 -20
  276. data/lib/graphql/types/relay/page_info.rb +2 -14
  277. data/lib/graphql/types/relay/page_info_behaviors.rb +25 -0
  278. data/lib/graphql/types/relay.rb +11 -3
  279. data/lib/graphql/types/string.rb +8 -2
  280. data/lib/graphql/unauthorized_error.rb +2 -2
  281. data/lib/graphql/union_type.rb +2 -0
  282. data/lib/graphql/upgrader/member.rb +1 -0
  283. data/lib/graphql/upgrader/schema.rb +1 -0
  284. data/lib/graphql/version.rb +1 -1
  285. data/lib/graphql.rb +65 -31
  286. data/readme.md +3 -6
  287. metadata +77 -112
  288. data/lib/graphql/execution/interpreter/hash_response.rb +0 -46
  289. data/lib/graphql/literal_validation_error.rb +0 -6
  290. data/lib/graphql/types/relay/base_field.rb +0 -22
  291. data/lib/graphql/types/relay/base_interface.rb +0 -29
  292. data/lib/graphql/types/relay/base_object.rb +0 -26
@@ -1,8 +1,12 @@
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
@@ -14,14 +18,19 @@ module GraphQL
14
18
  def execute(_operation, _root_type, query)
15
19
  runtime = evaluate(query)
16
20
  sync_lazies(query: query)
17
- runtime.final_value
21
+ runtime.final_result
18
22
  end
19
23
 
20
24
  def self.use(schema_class)
21
- schema_class.interpreter = true
22
- schema_class.query_execution_strategy(GraphQL::Execution::Interpreter)
23
- schema_class.mutation_execution_strategy(GraphQL::Execution::Interpreter)
24
- schema_class.subscription_execution_strategy(GraphQL::Execution::Interpreter)
25
+ if schema_class.interpreter?
26
+ definition_line = caller(2, 1).first
27
+ GraphQL::Deprecation.warn("GraphQL::Execution::Interpreter is now the default; remove `use GraphQL::Execution::Interpreter` from the schema definition (#{definition_line})")
28
+ else
29
+ schema_class.query_execution_strategy(self)
30
+ schema_class.mutation_execution_strategy(self)
31
+ schema_class.subscription_execution_strategy(self)
32
+ schema_class.add_subscription_extension_if_necessary
33
+ end
25
34
  end
26
35
 
27
36
  def self.begin_multiplex(multiplex)
@@ -47,7 +56,7 @@ module GraphQL
47
56
 
48
57
  def self.finish_query(query, _multiplex)
49
58
  {
50
- "data" => query.context.namespace(:interpreter)[:runtime].final_value
59
+ "data" => query.context.namespace(:interpreter)[:runtime].final_result
51
60
  }
52
61
  end
53
62
 
@@ -57,10 +66,7 @@ module GraphQL
57
66
  # Although queries in a multiplex _share_ an Interpreter instance,
58
67
  # they also have another item of state, which is private to that query
59
68
  # in particular, assign it here:
60
- runtime = Runtime.new(
61
- query: query,
62
- response: HashResponse.new,
63
- )
69
+ runtime = Runtime.new(query: query)
64
70
  query.context.namespace(:interpreter)[:runtime] = runtime
65
71
 
66
72
  query.trace("execute_query", {query: query}) do
@@ -81,11 +87,34 @@ module GraphQL
81
87
  final_values = queries.map do |query|
82
88
  runtime = query.context.namespace(:interpreter)[:runtime]
83
89
  # it might not be present if the query has an error
84
- runtime ? runtime.final_value : nil
90
+ runtime ? runtime.final_result : nil
85
91
  end
86
92
  final_values.compact!
87
93
  tracer.trace("execute_query_lazy", {multiplex: multiplex, query: query}) do
88
- Interpreter::Resolve.resolve_all(final_values)
94
+ Interpreter::Resolve.resolve_all(final_values, multiplex.dataloader)
95
+ end
96
+ queries.each do |query|
97
+ runtime = query.context.namespace(:interpreter)[:runtime]
98
+ if runtime
99
+ runtime.delete_interpreter_context(:current_path)
100
+ runtime.delete_interpreter_context(:current_field)
101
+ runtime.delete_interpreter_context(:current_object)
102
+ runtime.delete_interpreter_context(:current_arguments)
103
+ end
104
+ end
105
+ nil
106
+ end
107
+
108
+ class ListResultFailedError < GraphQL::Error
109
+ def initialize(value:, path:, field:)
110
+ message = "Failed to build a GraphQL list result for field `#{field.path}` at path `#{path.join(".")}`.\n".dup
111
+
112
+ message << "Expected `#{value.inspect}` (#{value.class}) to implement `.each` to satisfy the GraphQL return type `#{field.type.to_type_signature}`.\n"
113
+
114
+ if field.connection?
115
+ message << "\nThis field was treated as a Relay-style connection; add `connection: false` to the `field(...)` to disable this behavior."
116
+ end
117
+ super(message)
89
118
  end
90
119
  end
91
120
  end
@@ -48,7 +48,11 @@ module GraphQL
48
48
  end
49
49
  end
50
50
 
51
- if @value.is_a?(StandardError)
51
+ # `SKIP` was made into a subclass of `GraphQL::Error` to improve runtime performance
52
+ # (fewer clauses in a hot `case` block), but now it requires special handling here.
53
+ # I think it's still worth it for the performance win, but if the number of special
54
+ # cases grows, then maybe it's worth rethinking somehow.
55
+ if @value.is_a?(StandardError) && @value != GraphQL::Execution::Execute::SKIP
52
56
  raise @value
53
57
  else
54
58
  @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, @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`.
@@ -81,7 +91,7 @@ module GraphQL
81
91
  def selection(field_name, selected_type: @selected_type, arguments: nil)
82
92
  next_field_name = normalize_name(field_name)
83
93
 
84
- next_field_defn = FieldHelpers.get_field(@query.schema, selected_type, next_field_name)
94
+ next_field_defn = get_class_based_field(selected_type, next_field_name)
85
95
  if next_field_defn
86
96
  next_nodes = []
87
97
  @ast_nodes.each do |ast_node|
@@ -127,7 +137,7 @@ module GraphQL
127
137
 
128
138
  subselections_by_type.each do |type, ast_nodes_by_response_key|
129
139
  ast_nodes_by_response_key.each do |response_key, ast_nodes|
130
- field_defn = FieldHelpers.get_field(@query.schema, type, ast_nodes.first.name)
140
+ field_defn = get_class_based_field(type, ast_nodes.first.name)
131
141
  lookahead = Lookahead.new(query: @query, ast_nodes: ast_nodes, field: field_defn, owner_type: type)
132
142
  subselections.push(lookahead)
133
143
  end
@@ -203,12 +213,19 @@ module GraphQL
203
213
  end
204
214
  end
205
215
 
216
+ # Wrap get_field and ensure that it returns a GraphQL::Schema::Field.
217
+ # Remove this when legacy execution is removed.
218
+ def get_class_based_field(type, name)
219
+ f = @query.get_field(type, name)
220
+ f && f.type_class
221
+ end
222
+
206
223
  def skipped_by_directive?(ast_selection)
207
224
  ast_selection.directives.each do |directive|
208
225
  dir_defn = @query.schema.directives.fetch(directive.name)
209
226
  directive_class = dir_defn.type_class
210
227
  if directive_class
211
- dir_args = GraphQL::Execution::Lookahead::ArgumentHelpers.arguments(@query, dir_defn, directive)
228
+ dir_args = @query.arguments_for(directive, dir_defn)
212
229
  return true unless directive_class.static_include?(dir_args, @query.context)
213
230
  end
214
231
  end
@@ -227,7 +244,7 @@ module GraphQL
227
244
  elsif arguments.nil? || arguments.empty?
228
245
  selections_on_type[response_key] = [ast_selection]
229
246
  else
230
- field_defn = FieldHelpers.get_field(@query.schema, selected_type, ast_selection.name)
247
+ field_defn = get_class_based_field(selected_type, ast_selection.name)
231
248
  if arguments_match?(arguments, field_defn, ast_selection)
232
249
  selections_on_type[response_key] = [ast_selection]
233
250
  end
@@ -237,14 +254,14 @@ module GraphQL
237
254
  subselections_on_type = selections_on_type
238
255
  if (t = ast_selection.type)
239
256
  # Assuming this is valid, that `t` will be found.
240
- on_type = @query.schema.get_type(t.name).type_class
257
+ on_type = @query.get_type(t.name).type_class
241
258
  subselections_on_type = subselections_by_type[on_type] ||= {}
242
259
  end
243
260
  find_selections(subselections_by_type, subselections_on_type, on_type, ast_selection.selections, arguments)
244
261
  when GraphQL::Language::Nodes::FragmentSpread
245
262
  frag_defn = @query.fragments[ast_selection.name] || raise("Invariant: Can't look ahead to nonexistent fragment #{ast_selection.name} (found: #{@query.fragments.keys})")
246
263
  # Again, assuming a valid AST
247
- on_type = @query.schema.get_type(frag_defn.type.name).type_class
264
+ on_type = @query.get_type(frag_defn.type.name).type_class
248
265
  subselections_on_type = subselections_by_type[on_type] ||= {}
249
266
  find_selections(subselections_by_type, subselections_on_type, on_type, frag_defn.selections, arguments)
250
267
  else
@@ -278,115 +295,13 @@ module GraphQL
278
295
  end
279
296
 
280
297
  def arguments_match?(arguments, field_defn, field_node)
281
- query_kwargs = ArgumentHelpers.arguments(@query, field_defn, field_node)
298
+ query_kwargs = @query.arguments_for(field_node, field_defn)
282
299
  arguments.all? do |arg_name, arg_value|
283
300
  arg_name = normalize_keyword(arg_name)
284
301
  # Make sure the constraint is present with a matching value
285
302
  query_kwargs.key?(arg_name) && query_kwargs[arg_name] == arg_value
286
303
  end
287
304
  end
288
-
289
- # TODO Dedup with interpreter
290
- module ArgumentHelpers
291
- module_function
292
-
293
- def arguments(query, arg_owner, ast_node)
294
- kwarg_arguments = {}
295
- arg_defns = arg_owner.arguments
296
- ast_node.arguments.each do |arg|
297
- arg_defn = arg_defns[arg.name] || raise("Invariant: missing argument definition for #{arg.name.inspect} in #{arg_defns.keys} from #{arg_owner}")
298
- # Need to distinguish between client-provided `nil`
299
- # and nothing-at-all
300
- is_present, value = arg_to_value(query, arg_defn.type, arg.value)
301
- if is_present
302
- kwarg_arguments[arg_defn.keyword] = value
303
- end
304
- end
305
- arg_defns.each do |name, arg_defn|
306
- if arg_defn.default_value? && !kwarg_arguments.key?(arg_defn.keyword)
307
- kwarg_arguments[arg_defn.keyword] = arg_defn.default_value
308
- end
309
- end
310
- kwarg_arguments
311
- end
312
-
313
- # Get a Ruby-ready value from a client query.
314
- # @param graphql_object [Object] The owner of the field whose argument this is
315
- # @param arg_type [Class, GraphQL::Schema::NonNull, GraphQL::Schema::List]
316
- # @param ast_value [GraphQL::Language::Nodes::VariableIdentifier, String, Integer, Float, Boolean]
317
- # @return [Array(is_present, value)]
318
- def arg_to_value(query, arg_type, ast_value)
319
- if ast_value.is_a?(GraphQL::Language::Nodes::VariableIdentifier)
320
- # If it's not here, it will get added later
321
- if query.variables.key?(ast_value.name)
322
- return true, query.variables[ast_value.name]
323
- else
324
- return false, nil
325
- end
326
- elsif ast_value.is_a?(GraphQL::Language::Nodes::NullValue)
327
- return true, nil
328
- elsif arg_type.is_a?(GraphQL::Schema::NonNull)
329
- arg_to_value(query, arg_type.of_type, ast_value)
330
- elsif arg_type.is_a?(GraphQL::Schema::List)
331
- # Treat a single value like a list
332
- arg_value = Array(ast_value)
333
- list = []
334
- arg_value.map do |inner_v|
335
- _present, value = arg_to_value(query, arg_type.of_type, inner_v)
336
- list << value
337
- end
338
- return true, list
339
- elsif arg_type.is_a?(Class) && arg_type < GraphQL::Schema::InputObject
340
- # For these, `prepare` is applied during `#initialize`.
341
- # Pass `nil` so it will be skipped in `#arguments`.
342
- # What a mess.
343
- args = arguments(query, nil, arg_type, ast_value)
344
- # We're not tracking defaults_used, but for our purposes
345
- # we compare the value to the default value.
346
- return true, arg_type.new(ruby_kwargs: args, context: query.context, defaults_used: nil)
347
- else
348
- flat_value = flatten_ast_value(query, ast_value)
349
- return true, arg_type.coerce_input(flat_value, query.context)
350
- end
351
- end
352
-
353
- def flatten_ast_value(query, v)
354
- case v
355
- when GraphQL::Language::Nodes::Enum
356
- v.name
357
- when GraphQL::Language::Nodes::InputObject
358
- h = {}
359
- v.arguments.each do |arg|
360
- h[arg.name] = flatten_ast_value(query, arg.value)
361
- end
362
- h
363
- when Array
364
- v.map { |v2| flatten_ast_value(query, v2) }
365
- when GraphQL::Language::Nodes::VariableIdentifier
366
- flatten_ast_value(query.variables[v.name])
367
- else
368
- v
369
- end
370
- end
371
- end
372
-
373
- # TODO dedup with interpreter
374
- module FieldHelpers
375
- module_function
376
-
377
- def get_field(schema, owner_type, field_name)
378
- field_defn = owner_type.get_field(field_name)
379
- field_defn ||= if owner_type == schema.query.type_class && (entry_point_field = schema.introspection_system.entry_point(name: field_name))
380
- entry_point_field.type_class
381
- elsif (dynamic_field = schema.introspection_system.dynamic_field(name: field_name))
382
- dynamic_field.type_class
383
- else
384
- nil
385
- end
386
-
387
- field_defn
388
- end
389
- end
390
305
  end
391
306
  end
392
307
  end
@@ -29,13 +29,14 @@ module GraphQL
29
29
 
30
30
  include Tracing::Traceable
31
31
 
32
- attr_reader :context, :queries, :schema, :max_complexity
32
+ attr_reader :context, :queries, :schema, :max_complexity, :dataloader
33
33
  def initialize(schema:, queries:, context:, max_complexity:)
34
34
  @schema = schema
35
35
  @queries = queries
36
+ @queries.each { |q| q.multiplex = self }
36
37
  @context = context
37
- # TODO remove support for global tracers
38
- @tracers = schema.tracers + GraphQL::Tracing.tracers + (context[:tracers] || [])
38
+ @dataloader = @context[:dataloader] ||= @schema.dataloader_class.new
39
+ @tracers = schema.tracers + (context[:tracers] || [])
39
40
  # Support `context: {backtrace: true}`
40
41
  if context[:backtrace] && !@tracers.include?(GraphQL::Backtrace::Tracer)
41
42
  @tracers << GraphQL::Backtrace::Tracer
@@ -73,6 +74,24 @@ module GraphQL
73
74
  end
74
75
  end
75
76
 
77
+ # @param query [GraphQL::Query]
78
+ def begin_query(results, idx, query, multiplex)
79
+ operation = query.selected_operation
80
+ result = if operation.nil? || !query.valid? || query.context.errors.any?
81
+ NO_OPERATION
82
+ else
83
+ begin
84
+ # These were checked to be the same in `#supports_multiplexing?`
85
+ query.schema.query_execution_strategy.begin_query(query, multiplex)
86
+ rescue GraphQL::ExecutionError => err
87
+ query.context.errors << err
88
+ NO_OPERATION
89
+ end
90
+ end
91
+ results[idx] = result
92
+ nil
93
+ end
94
+
76
95
  private
77
96
 
78
97
  def run_as_multiplex(multiplex)
@@ -80,20 +99,28 @@ module GraphQL
80
99
  multiplex.schema.query_execution_strategy.begin_multiplex(multiplex)
81
100
  queries = multiplex.queries
82
101
  # Do as much eager evaluation of the query as possible
83
- results = queries.map do |query|
84
- begin_query(query, multiplex)
102
+ results = []
103
+ queries.each_with_index do |query, idx|
104
+ multiplex.dataloader.append_job { begin_query(results, idx, query, multiplex) }
85
105
  end
86
106
 
107
+ multiplex.dataloader.run
108
+
87
109
  # Then, work through lazy results in a breadth-first way
88
- multiplex.schema.query_execution_strategy.finish_multiplex(results, multiplex)
110
+ multiplex.dataloader.append_job {
111
+ multiplex.schema.query_execution_strategy.finish_multiplex(results, multiplex)
112
+ }
113
+ multiplex.dataloader.run
89
114
 
90
115
  # Then, find all errors and assign the result to the query object
91
- results.each_with_index.map do |data_result, idx|
116
+ results.each_with_index do |data_result, idx|
92
117
  query = queries[idx]
93
118
  finish_query(data_result, query, multiplex)
94
119
  # Get the Query::Result, not the Hash
95
- query.result
120
+ results[idx] = query.result
96
121
  end
122
+
123
+ results
97
124
  rescue Exception
98
125
  # TODO rescue at a higher level so it will catch errors in analysis, too
99
126
  # Assign values here so that the query's `@executed` becomes true
@@ -101,23 +128,6 @@ module GraphQL
101
128
  raise
102
129
  end
103
130
 
104
- # @param query [GraphQL::Query]
105
- # @return [Hash] The initial result (may not be finished if there are lazy values)
106
- def begin_query(query, multiplex)
107
- operation = query.selected_operation
108
- if operation.nil? || !query.valid? || query.context.errors.any?
109
- NO_OPERATION
110
- else
111
- begin
112
- # These were checked to be the same in `#supports_multiplexing?`
113
- query.schema.query_execution_strategy.begin_query(query, multiplex)
114
- rescue GraphQL::ExecutionError => err
115
- query.context.errors << err
116
- NO_OPERATION
117
- end
118
- end
119
- end
120
-
121
131
  # @param data_result [Hash] The result for the "data" key, if any
122
132
  # @param query [GraphQL::Query] The query which was run
123
133
  # @return [Hash] final result of this query, including all values and errors
@@ -145,6 +155,8 @@ module GraphQL
145
155
 
146
156
  # use the old `query_execution_strategy` etc to run this query
147
157
  def run_one_legacy(schema, query)
158
+ GraphQL::Deprecation.warn "Multiplex.run_one_legacy will be removed from GraphQL-Ruby 2.0, upgrade to the Interpreter to avoid this deprecated codepath: https://graphql-ruby.org/queries/interpreter.html"
159
+
148
160
  query.result_values = if !query.valid?
149
161
  all_errors = query.validation_errors + query.analysis_errors + query.context.errors
150
162
  if all_errors.any?
data/lib/graphql/field.rb CHANGED
@@ -154,7 +154,7 @@ module GraphQL
154
154
  end
155
155
 
156
156
  def name=(new_name)
157
- old_name = @name
157
+ old_name = defined?(@name) ? @name : nil
158
158
  @name = new_name
159
159
 
160
160
  if old_name != new_name && @resolve_proc.is_a?(Field::Resolve::NameResolve)
@@ -207,6 +207,10 @@ module GraphQL
207
207
  metadata[:type_class]
208
208
  end
209
209
 
210
+ def get_argument(argument_name)
211
+ arguments[argument_name]
212
+ end
213
+
210
214
  private
211
215
 
212
216
  def build_default_resolver
@@ -2,6 +2,10 @@
2
2
  module GraphQL
3
3
  # @api deprecated
4
4
  class Function
5
+ def self.inherited(subclass)
6
+ GraphQL::Deprecation.warn "GraphQL::Function (used for #{subclass}) will be removed from GraphQL-Ruby 2.0, please upgrade to resolvers: https://graphql-ruby.org/fields/resolvers.html"
7
+ end
8
+
5
9
  # @return [Hash<String => GraphQL::Argument>] Arguments, keyed by name
6
10
  def arguments
7
11
  self.class.arguments
@@ -2,6 +2,8 @@
2
2
  module GraphQL
3
3
  # @api deprecated
4
4
  class InputObjectType < GraphQL::BaseType
5
+ extend Define::InstanceDefinable::DeprecatedDefine
6
+
5
7
  accepts_definitions(
6
8
  :arguments, :mutation,
7
9
  input_field: GraphQL::Define::AssignArgument,
@@ -58,6 +60,10 @@ module GraphQL
58
60
  result
59
61
  end
60
62
 
63
+ def get_argument(argument_name)
64
+ arguments[argument_name]
65
+ end
66
+
61
67
  private
62
68
 
63
69
  def coerce_non_null_input(value, ctx)
@@ -0,0 +1,17 @@
1
+ # frozen_string_literal: true
2
+ module GraphQL
3
+ # This error is raised when `Types::Int` is given an input value outside of 32-bit integer range.
4
+ #
5
+ # For really big integer values, consider `GraphQL::Types::BigInt`
6
+ #
7
+ # @see GraphQL::Types::Int which raises this error
8
+ class IntegerDecodingError < GraphQL::RuntimeTypeError
9
+ # The value which couldn't be decoded
10
+ attr_reader :integer_value
11
+
12
+ def initialize(value)
13
+ @integer_value = value
14
+ super("Integer out of bounds: #{value}. \nConsider using GraphQL::Types::BigInt instead.")
15
+ end
16
+ end
17
+ end
@@ -12,9 +12,25 @@ module GraphQL
12
12
  # The value which couldn't be encoded
13
13
  attr_reader :integer_value
14
14
 
15
- def initialize(value)
15
+ # @return [GraphQL::Schema::Field] The field that returned a too-big integer
16
+ attr_reader :field
17
+
18
+ # @return [Array<String, Integer>] Where the field appeared in the GraphQL response
19
+ attr_reader :path
20
+
21
+ def initialize(value, context:)
16
22
  @integer_value = value
17
- super("Integer out of bounds: #{value}. \nConsider using ID or GraphQL::Types::BigInt instead.")
23
+ @field = context[:current_field]
24
+ @path = context[:current_path]
25
+ message = "Integer out of bounds: #{value}".dup
26
+ if @path
27
+ message << " @ #{@path.join(".")}"
28
+ end
29
+ if @field
30
+ message << " (#{@field.path})"
31
+ end
32
+ message << ". Consider using ID or GraphQL::Types::BigInt instead."
33
+ super(message)
18
34
  end
19
35
  end
20
36
  end
@@ -2,9 +2,12 @@
2
2
  module GraphQL
3
3
  # @api deprecated
4
4
  class InterfaceType < GraphQL::BaseType
5
+ extend Define::InstanceDefinable::DeprecatedDefine
6
+
5
7
  accepts_definitions :fields, :orphan_types, :resolve_type, field: GraphQL::Define::AssignObjectField
6
8
 
7
9
  attr_accessor :fields, :orphan_types, :resolve_type_proc
10
+ attr_writer :type_membership_class
8
11
  ensure_defined :fields, :orphan_types, :resolve_type_proc, :resolve_type
9
12
 
10
13
  def initialize
@@ -61,5 +64,9 @@ module GraphQL
61
64
  type_name = type.is_a?(String) ? type : type.graphql_name
62
65
  !get_possible_type(type_name, ctx).nil?
63
66
  end
67
+
68
+ def type_membership_class
69
+ @type_membership_class || GraphQL::Schema::TypeMembership
70
+ end
64
71
  end
65
72
  end
@@ -14,12 +14,12 @@ module GraphQL
14
14
  end
15
15
 
16
16
  def [](key)
17
- warn "#{self.class}#[] is deprecated; use `operation_definitions[]` instead"
17
+ GraphQL::Deprecation.warn "#{self.class}#[] is deprecated; use `operation_definitions[]` instead"
18
18
  operation_definitions[key]
19
19
  end
20
20
 
21
21
  def each(&block)
22
- warn "#{self.class}#each is deprecated; use `operation_definitions.each` instead"
22
+ GraphQL::Deprecation.warn "#{self.class}#each is deprecated; use `operation_definitions.each` instead"
23
23
  operation_definitions.each(&block)
24
24
  end
25
25
  end
@@ -60,7 +60,7 @@ module GraphQL
60
60
 
61
61
  # @return [Hash<String, Node>] Roots of this query
62
62
  def operations
63
- warn "#{self.class}#operations is deprecated; use `document.operation_definitions` instead"
63
+ GraphQL::Deprecation.warn "#{self.class}#operations is deprecated; use `document.operation_definitions` instead"
64
64
  @document.operation_definitions
65
65
  end
66
66
 
@@ -66,11 +66,11 @@ module GraphQL
66
66
  # Call the block for each type in `self`.
67
67
  # This uses the simplest possible expression of `self`,
68
68
  # so if this scope is defined by an abstract type, it gets yielded.
69
- def each
69
+ def each(&block)
70
70
  if @abstract_type
71
71
  yield(@type)
72
72
  else
73
- @types.each { |t| yield(t) }
73
+ @types.each(&block)
74
74
  end
75
75
  end
76
76
 
@@ -23,11 +23,11 @@ module GraphQL
23
23
 
24
24
  # Traverse a node in a rewritten query tree,
25
25
  # visiting the node itself and each of its typed children.
26
- def each_node(node)
26
+ def each_node(node, &block)
27
27
  yield(node)
28
28
  node.typed_children.each do |obj_type, children|
29
29
  children.each do |name, node|
30
- each_node(node) { |n| yield(n) }
30
+ each_node(node, &block)
31
31
  end
32
32
  end
33
33
  end
@@ -10,15 +10,19 @@ module GraphQL
10
10
  "skipping a field. Directives provide this by describing additional information "\
11
11
  "to the executor."
12
12
  field :name, String, null: false, method: :graphql_name
13
- field :description, String, null: true
13
+ field :description, String
14
14
  field :locations, [GraphQL::Schema::LateBoundType.new("__DirectiveLocation")], null: false
15
- field :args, [GraphQL::Schema::LateBoundType.new("__InputValue")], null: false
15
+ field :args, [GraphQL::Schema::LateBoundType.new("__InputValue")], null: false do
16
+ argument :include_deprecated, Boolean, required: false, default_value: false
17
+ end
16
18
  field :on_operation, Boolean, null: false, deprecation_reason: "Use `locations`.", method: :on_operation?
17
19
  field :on_fragment, Boolean, null: false, deprecation_reason: "Use `locations`.", method: :on_fragment?
18
20
  field :on_field, Boolean, null: false, deprecation_reason: "Use `locations`.", method: :on_field?
19
21
 
20
- def args
21
- @context.warden.arguments(@object)
22
+ def args(include_deprecated:)
23
+ args = @context.warden.arguments(@object)
24
+ args = args.reject(&:deprecation_reason) unless include_deprecated
25
+ args
22
26
  end
23
27
  end
24
28
  end
@@ -3,8 +3,8 @@ module GraphQL
3
3
  module Introspection
4
4
  class EntryPoints < Introspection::BaseObject
5
5
  field :__schema, GraphQL::Schema::LateBoundType.new("__Schema"), "This GraphQL schema", null: false
6
- field :__type, GraphQL::Schema::LateBoundType.new("__Type"), "A type in the GraphQL system", null: true do
7
- argument :name, String, required: true
6
+ field :__type, GraphQL::Schema::LateBoundType.new("__Type"), "A type in the GraphQL system" do
7
+ argument :name, String
8
8
  end
9
9
 
10
10
  def __schema
@@ -7,9 +7,9 @@ module GraphQL
7
7
  "placeholder for a string or numeric value. However an Enum value is returned in "\
8
8
  "a JSON response as a string."
9
9
  field :name, String, null: false
10
- field :description, String, null: true
10
+ field :description, String
11
11
  field :is_deprecated, Boolean, null: false
12
- field :deprecation_reason, String, null: true
12
+ field :deprecation_reason, String
13
13
 
14
14
  def name
15
15
  object.graphql_name