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,4 +1,5 @@
1
1
  # frozen_string_literal: true
2
+ require "graphql/schema/addition"
2
3
  require "graphql/schema/base_64_encoder"
3
4
  require "graphql/schema/catchall_middleware"
4
5
  require "graphql/schema/default_parse_error"
@@ -21,6 +22,7 @@ require "graphql/schema/validation"
21
22
  require "graphql/schema/warden"
22
23
  require "graphql/schema/build_from_definition"
23
24
 
25
+ require "graphql/schema/validator"
24
26
  require "graphql/schema/member"
25
27
  require "graphql/schema/wrapper"
26
28
  require "graphql/schema/list"
@@ -40,6 +42,7 @@ require "graphql/schema/directive/deprecated"
40
42
  require "graphql/schema/directive/include"
41
43
  require "graphql/schema/directive/skip"
42
44
  require "graphql/schema/directive/feature"
45
+ require "graphql/schema/directive/flagged"
43
46
  require "graphql/schema/directive/transform"
44
47
  require "graphql/schema/type_membership"
45
48
 
@@ -80,8 +83,17 @@ module GraphQL
80
83
  extend GraphQL::Schema::Member::AcceptsDefinition
81
84
  extend GraphQL::Schema::Member::HasAstNode
82
85
  include GraphQL::Define::InstanceDefinable
86
+ extend GraphQL::Define::InstanceDefinable::DeprecatedDefine
83
87
  extend GraphQL::Schema::FindInheritedValue
84
88
 
89
+ class DuplicateTypeNamesError < GraphQL::Error
90
+ def initialize(type_name:, first_definition:, second_definition:, path:)
91
+ super("Multiple definitions for `#{type_name}`. Previously found #{first_definition.inspect} (#{first_definition.class}), then found #{second_definition.inspect} (#{second_definition.class}) at #{path.join(".")}")
92
+ end
93
+ end
94
+
95
+ class DuplicateNamesError < GraphQL::Error; end
96
+
85
97
  class UnresolvedLateBoundTypeError < GraphQL::Error
86
98
  attr_reader :type
87
99
  def initialize(type:)
@@ -90,9 +102,68 @@ module GraphQL
90
102
  end
91
103
  end
92
104
 
105
+ module LazyHandlingMethods
106
+ # Call the given block at the right time, either:
107
+ # - Right away, if `value` is not registered with `lazy_resolve`
108
+ # - After resolving `value`, if it's registered with `lazy_resolve` (eg, `Promise`)
109
+ # @api private
110
+ def after_lazy(value, &block)
111
+ if lazy?(value)
112
+ GraphQL::Execution::Lazy.new do
113
+ result = sync_lazy(value)
114
+ # The returned result might also be lazy, so check it, too
115
+ after_lazy(result, &block)
116
+ end
117
+ else
118
+ yield(value) if block_given?
119
+ end
120
+ end
121
+
122
+ # Override this method to handle lazy objects in a custom way.
123
+ # @param value [Object] an instance of a class registered with {.lazy_resolve}
124
+ # @return [Object] A GraphQL-ready (non-lazy) object
125
+ # @api private
126
+ def sync_lazy(value)
127
+ lazy_method = lazy_method_name(value)
128
+ if lazy_method
129
+ synced_value = value.public_send(lazy_method)
130
+ sync_lazy(synced_value)
131
+ else
132
+ value
133
+ end
134
+ end
135
+
136
+ # @return [Symbol, nil] The method name to lazily resolve `obj`, or nil if `obj`'s class wasn't registered with {#lazy_resolve}.
137
+ def lazy_method_name(obj)
138
+ lazy_methods.get(obj)
139
+ end
140
+
141
+ # @return [Boolean] True if this object should be lazily resolved
142
+ def lazy?(obj)
143
+ !!lazy_method_name(obj)
144
+ end
145
+
146
+ # Return a lazy if any of `maybe_lazies` are lazy,
147
+ # otherwise, call the block eagerly and return the result.
148
+ # @param maybe_lazies [Array]
149
+ # @api private
150
+ def after_any_lazies(maybe_lazies)
151
+ if maybe_lazies.any? { |l| lazy?(l) }
152
+ GraphQL::Execution::Lazy.all(maybe_lazies).then do |result|
153
+ yield result
154
+ end
155
+ else
156
+ yield maybe_lazies
157
+ end
158
+ end
159
+ end
160
+
161
+ include LazyHandlingMethods
162
+ extend LazyHandlingMethods
163
+
93
164
  accepts_definitions \
94
165
  :query_execution_strategy, :mutation_execution_strategy, :subscription_execution_strategy,
95
- :max_depth, :max_complexity, :default_max_page_size,
166
+ :validate_timeout, :validate_max_errors, :max_depth, :max_complexity, :default_max_page_size,
96
167
  :orphan_types, :resolve_type, :type_error, :parse_error,
97
168
  :error_bubbling,
98
169
  :raise_definition_error,
@@ -116,7 +187,7 @@ module GraphQL
116
187
  },
117
188
  query_analyzer: ->(schema, analyzer) {
118
189
  if analyzer == GraphQL::Authorization::Analyzer
119
- warn("The Authorization query analyzer is deprecated. Authorizing at query runtime is generally a better idea.")
190
+ GraphQL::Deprecation.warn("The Authorization query analyzer is deprecated. Authorizing at query runtime is generally a better idea.")
120
191
  end
121
192
  schema.query_analyzers << analyzer
122
193
  },
@@ -131,7 +202,7 @@ module GraphQL
131
202
  attr_accessor \
132
203
  :query, :mutation, :subscription,
133
204
  :query_execution_strategy, :mutation_execution_strategy, :subscription_execution_strategy,
134
- :max_depth, :max_complexity, :default_max_page_size,
205
+ :validate_timeout, :validate_max_errors, :max_depth, :max_complexity, :default_max_page_size,
135
206
  :orphan_types, :directives,
136
207
  :query_analyzers, :multiplex_analyzers, :instrumenters, :lazy_methods,
137
208
  :cursor_encoder,
@@ -216,11 +287,11 @@ module GraphQL
216
287
  @lazy_methods = GraphQL::Execution::Lazy::LazyMethodMap.new
217
288
  @lazy_methods.set(GraphQL::Execution::Lazy, :value)
218
289
  @cursor_encoder = Base64Encoder
219
- # Default to the built-in execution strategy:
290
+ # For schema instances, default to legacy runtime modules
220
291
  @analysis_engine = GraphQL::Analysis
221
- @query_execution_strategy = self.class.default_execution_strategy
222
- @mutation_execution_strategy = self.class.default_execution_strategy
223
- @subscription_execution_strategy = self.class.default_execution_strategy
292
+ @query_execution_strategy = GraphQL::Execution::Execute
293
+ @mutation_execution_strategy = GraphQL::Execution::Execute
294
+ @subscription_execution_strategy = GraphQL::Execution::Execute
224
295
  @default_mask = GraphQL::Schema::NullMask
225
296
  @rebuilding_artifacts = false
226
297
  @context_class = GraphQL::Query::Context
@@ -235,12 +306,11 @@ module GraphQL
235
306
 
236
307
  # @return [Boolean] True if using the new {GraphQL::Execution::Interpreter}
237
308
  def interpreter?
238
- @interpreter
309
+ query_execution_strategy == GraphQL::Execution::Interpreter &&
310
+ mutation_execution_strategy == GraphQL::Execution::Interpreter &&
311
+ subscription_execution_strategy == GraphQL::Execution::Interpreter
239
312
  end
240
313
 
241
- # @api private
242
- attr_writer :interpreter
243
-
244
314
  def inspect
245
315
  "#<#{self.class.name} ...>"
246
316
  end
@@ -288,24 +358,7 @@ module GraphQL
288
358
  # For forwards-compatibility with Schema classes
289
359
  alias :graphql_definition :itself
290
360
 
291
- # Validate a query string according to this schema.
292
- # @param string_or_document [String, GraphQL::Language::Nodes::Document]
293
- # @return [Array<GraphQL::StaticValidation::Error >]
294
- def validate(string_or_document, rules: nil, context: nil)
295
- doc = if string_or_document.is_a?(String)
296
- GraphQL.parse(string_or_document)
297
- else
298
- string_or_document
299
- end
300
- query = GraphQL::Query.new(self, document: doc, context: context)
301
- validator_opts = { schema: self }
302
- rules && (validator_opts[:rules] = rules)
303
- validator = GraphQL::StaticValidation::Validator.new(**validator_opts)
304
- res = validator.validate(query)
305
- res[:errors]
306
- end
307
-
308
- def define(**kwargs, &block)
361
+ def deprecated_define(**kwargs, &block)
309
362
  super
310
363
  ensure_defined
311
364
  # Assert that all necessary configs are present:
@@ -488,11 +541,20 @@ module GraphQL
488
541
  # @param context [GraphQL::Query::Context] The context for the current query
489
542
  # @return [Array<GraphQL::ObjectType>] types which belong to `type_defn` in this schema
490
543
  def possible_types(type_defn, context = GraphQL::Query::NullContext)
491
- @possible_types ||= GraphQL::Schema::PossibleTypes.new(self)
492
- @possible_types.possible_types(type_defn, context)
544
+ if context == GraphQL::Query::NullContext
545
+ @possible_types ||= GraphQL::Schema::PossibleTypes.new(self)
546
+ @possible_types.possible_types(type_defn, context)
547
+ else
548
+ # Use the incoming context to cache this instance --
549
+ # if it were cached on the schema, we'd have a memory leak
550
+ # https://github.com/rmosolgo/graphql-ruby/issues/2878
551
+ ns = context.namespace(:possible_types)
552
+ per_query_possible_types = ns[:possible_types] ||= GraphQL::Schema::PossibleTypes.new(self)
553
+ per_query_possible_types.possible_types(type_defn, context)
554
+ end
493
555
  end
494
556
 
495
- # @see [GraphQL::Schema::Warden] Resticted access to root types
557
+ # @see [GraphQL::Schema::Warden] Restricted access to root types
496
558
  # @return [GraphQL::ObjectType, nil]
497
559
  def root_type_for_operation(operation)
498
560
  case operation
@@ -636,6 +698,7 @@ module GraphQL
636
698
  def_delegators :_schema_class, :unauthorized_object, :unauthorized_field, :inaccessible_fields
637
699
  def_delegators :_schema_class, :directive
638
700
  def_delegators :_schema_class, :error_handler
701
+ def_delegators :_schema_class, :validate
639
702
 
640
703
 
641
704
  # Given this schema member, find the class-based definition object
@@ -713,31 +776,29 @@ module GraphQL
713
776
  # @param default_resolve [<#call(type, field, obj, args, ctx)>] A callable for handling field resolution
714
777
  # @param parser [Object] An object for handling definition string parsing (must respond to `parse`)
715
778
  # @param using [Hash] Plugins to attach to the created schema with `use(key, value)`
716
- # @param interpreter [Boolean] If false, the legacy {Execution::Execute} runtime will be used
717
779
  # @return [Class] the schema described by `document`
718
- def self.from_definition(definition_or_path, default_resolve: BuildFromDefinition::DefaultResolve, interpreter: true, parser: BuildFromDefinition::DefaultParser, using: {})
780
+ def self.from_definition(definition_or_path, default_resolve: nil, parser: GraphQL.default_parser, using: {})
719
781
  # If the file ends in `.graphql`, treat it like a filepath
720
- definition = if definition_or_path.end_with?(".graphql")
721
- File.read(definition_or_path)
782
+ if definition_or_path.end_with?(".graphql")
783
+ GraphQL::Schema::BuildFromDefinition.from_definition_path(
784
+ definition_or_path,
785
+ default_resolve: default_resolve,
786
+ parser: parser,
787
+ using: using,
788
+ )
722
789
  else
723
- definition_or_path
790
+ GraphQL::Schema::BuildFromDefinition.from_definition(
791
+ definition_or_path,
792
+ default_resolve: default_resolve,
793
+ parser: parser,
794
+ using: using,
795
+ )
724
796
  end
725
- GraphQL::Schema::BuildFromDefinition.from_definition(definition, default_resolve: default_resolve, parser: parser, using: using, interpreter: interpreter)
726
797
  end
727
798
 
728
799
  # Error that is raised when [#Schema#from_definition] is passed an invalid schema definition string.
729
800
  class InvalidDocumentError < Error; end;
730
801
 
731
- # @return [Symbol, nil] The method name to lazily resolve `obj`, or nil if `obj`'s class wasn't registered wtih {#lazy_resolve}.
732
- def lazy_method_name(obj)
733
- @lazy_methods.get(obj)
734
- end
735
-
736
- # @return [Boolean] True if this object should be lazily resolved
737
- def lazy?(obj)
738
- !!lazy_method_name(obj)
739
- end
740
-
741
802
  # Return the GraphQL IDL for the schema
742
803
  # @param context [Hash]
743
804
  # @param only [<#call(member, ctx)>]
@@ -762,7 +823,7 @@ module GraphQL
762
823
  # @param except [<#call(member, ctx)>]
763
824
  # @return [Hash] GraphQL result
764
825
  def as_json(only: nil, except: nil, context: {})
765
- execute(Introspection::INTROSPECTION_QUERY, only: only, except: except, context: context).to_h
826
+ execute(Introspection.query(include_deprecated_args: true), only: only, except: except, context: context).to_h
766
827
  end
767
828
 
768
829
  # Returns the JSON response of {Introspection::INTROSPECTION_QUERY}.
@@ -787,7 +848,6 @@ module GraphQL
787
848
  def_delegators :graphql_definition,
788
849
  # Execution
789
850
  :execution_strategy_for_operation,
790
- :validate, :multiplex_analyzers,
791
851
  # Configuration
792
852
  :metadata, :redefine,
793
853
  :id_from_object_proc, :object_from_id_proc,
@@ -800,8 +860,8 @@ module GraphQL
800
860
  # Returns the JSON response of {Introspection::INTROSPECTION_QUERY}.
801
861
  # @see {#as_json}
802
862
  # @return [String]
803
- def to_json(*args)
804
- JSON.pretty_generate(as_json(*args))
863
+ def to_json(**args)
864
+ JSON.pretty_generate(as_json(**args))
805
865
  end
806
866
 
807
867
  # Return the Hash response of {Introspection::INTROSPECTION_QUERY}.
@@ -810,7 +870,7 @@ module GraphQL
810
870
  # @param except [<#call(member, ctx)>]
811
871
  # @return [Hash] GraphQL result
812
872
  def as_json(only: nil, except: nil, context: {})
813
- execute(Introspection::INTROSPECTION_QUERY, only: only, except: except, context: context).to_h
873
+ execute(Introspection.query(include_deprecated_args: true), only: only, except: except, context: context).to_h
814
874
  end
815
875
 
816
876
  # Return the GraphQL IDL for the schema
@@ -875,6 +935,8 @@ module GraphQL
875
935
  schema_defn.query = query && query.graphql_definition
876
936
  schema_defn.mutation = mutation && mutation.graphql_definition
877
937
  schema_defn.subscription = subscription && subscription.graphql_definition
938
+ schema_defn.validate_timeout = validate_timeout
939
+ schema_defn.validate_max_errors = validate_max_errors
878
940
  schema_defn.max_complexity = max_complexity
879
941
  schema_defn.error_bubbling = error_bubbling
880
942
  schema_defn.max_depth = max_depth
@@ -896,6 +958,7 @@ module GraphQL
896
958
  schema_defn.cursor_encoder = cursor_encoder
897
959
  schema_defn.tracers.concat(tracers)
898
960
  schema_defn.query_analyzers.concat(query_analyzers)
961
+ schema_defn.analysis_engine = analysis_engine
899
962
 
900
963
  schema_defn.middleware.concat(all_middleware)
901
964
  schema_defn.multiplex_analyzers.concat(multiplex_analyzers)
@@ -913,7 +976,7 @@ module GraphQL
913
976
  schema_defn.lazy_methods.set(lazy_class, value_method)
914
977
  end
915
978
 
916
- rescues.each do |err_class, handler|
979
+ error_handler.each_rescue do |err_class, handler|
917
980
  schema_defn.rescue_from(err_class, &handler)
918
981
  end
919
982
 
@@ -922,6 +985,11 @@ module GraphQL
922
985
  if !schema_defn.interpreter?
923
986
  schema_defn.instrumenters[:query] << GraphQL::Schema::Member::Instrumentation
924
987
  end
988
+
989
+ if new_connections?
990
+ schema_defn.connections = self.connections
991
+ end
992
+
925
993
  schema_defn.send(:rebuild_artifacts)
926
994
 
927
995
  schema_defn
@@ -930,20 +998,78 @@ module GraphQL
930
998
  # Build a map of `{ name => type }` and return it
931
999
  # @return [Hash<String => Class>] A dictionary of type classes by their GraphQL name
932
1000
  # @see get_type Which is more efficient for finding _one type_ by name, because it doesn't merge hashes.
933
- def types
934
- non_introspection_types.merge(introspection_system.types)
1001
+ def types(context = GraphQL::Query::NullContext)
1002
+ all_types = non_introspection_types.merge(introspection_system.types)
1003
+ visible_types = {}
1004
+ all_types.each do |k, v|
1005
+ visible_types[k] =if v.is_a?(Array)
1006
+ visible_t = nil
1007
+ v.each do |t|
1008
+ if t.visible?(context)
1009
+ if visible_t.nil?
1010
+ visible_t = t
1011
+ else
1012
+ raise DuplicateNamesError, "Found two visible type definitions for `#{k}`: #{visible_t.inspect}, #{t.inspect}"
1013
+ end
1014
+ end
1015
+ end
1016
+ visible_t
1017
+ else
1018
+ v
1019
+ end
1020
+ end
1021
+ visible_types
935
1022
  end
936
1023
 
937
1024
  # @param type_name [String]
938
1025
  # @return [Module, nil] A type, or nil if there's no type called `type_name`
939
- def get_type(type_name)
940
- own_types[type_name] ||
941
- introspection_system.types[type_name] ||
942
- find_inherited_value(:types, EMPTY_HASH)[type_name]
1026
+ def get_type(type_name, context = GraphQL::Query::NullContext)
1027
+ local_entry = own_types[type_name]
1028
+ type_defn = case local_entry
1029
+ when nil
1030
+ nil
1031
+ when Array
1032
+ visible_t = nil
1033
+ warden = Warden.from_context(context)
1034
+ local_entry.each do |t|
1035
+ if warden.visible_type?(t, context)
1036
+ if visible_t.nil?
1037
+ visible_t = t
1038
+ else
1039
+ raise DuplicateNamesError, "Found two visible type definitions for `#{type_name}`: #{visible_t.inspect}, #{t.inspect}"
1040
+ end
1041
+ end
1042
+ end
1043
+ visible_t
1044
+ when Module
1045
+ local_entry
1046
+ else
1047
+ raise "Invariant: unexpected own_types[#{type_name.inspect}]: #{local_entry.inspect}"
1048
+ end
1049
+
1050
+ type_defn ||
1051
+ introspection_system.types[type_name] || # todo context-specific introspection?
1052
+ (superclass.respond_to?(:get_type) ? superclass.get_type(type_name, context) : nil)
943
1053
  end
944
1054
 
1055
+ # @api private
1056
+ attr_writer :connections
1057
+
945
1058
  # @return [GraphQL::Pagination::Connections] if installed
946
- attr_accessor :connections
1059
+ def connections
1060
+ if defined?(@connections)
1061
+ @connections
1062
+ else
1063
+ inherited_connections = find_inherited_value(:connections, nil)
1064
+ # This schema is part of an inheritance chain which is using new connections,
1065
+ # make a new instance, so we don't pollute the upstream one.
1066
+ if inherited_connections
1067
+ @connections = Pagination::Connections.new(schema: self)
1068
+ else
1069
+ nil
1070
+ end
1071
+ end
1072
+ end
947
1073
 
948
1074
  def new_connections?
949
1075
  !!connections
@@ -983,6 +1109,7 @@ module GraphQL
983
1109
  raise GraphQL::Error, "Second definition of `subscription(...)` (#{new_subscription_object.inspect}) is invalid, already configured with #{@subscription_object.inspect}"
984
1110
  else
985
1111
  @subscription_object = new_subscription_object
1112
+ add_subscription_extension_if_necessary
986
1113
  add_type_and_traverse(new_subscription_object, root: true)
987
1114
  nil
988
1115
  end
@@ -991,7 +1118,7 @@ module GraphQL
991
1118
  end
992
1119
  end
993
1120
 
994
- # @see [GraphQL::Schema::Warden] Resticted access to root types
1121
+ # @see [GraphQL::Schema::Warden] Restricted access to root types
995
1122
  # @return [GraphQL::ObjectType, nil]
996
1123
  def root_type_for_operation(operation)
997
1124
  case operation
@@ -1019,7 +1146,17 @@ module GraphQL
1019
1146
  if type.kind.union?
1020
1147
  type.possible_types(context: context)
1021
1148
  else
1022
- own_possible_types[type.graphql_name] ||
1149
+ stored_possible_types = own_possible_types[type.graphql_name]
1150
+ visible_possible_types = if stored_possible_types && type.kind.interface?
1151
+ stored_possible_types.select do |possible_type|
1152
+ # Use `.graphql_name` comparison to match legacy vs class-based types.
1153
+ # When we don't need to support legacy `.define` types, use `.include?(type)` instead.
1154
+ possible_type.interfaces(context).any? { |interface| interface.graphql_name == type.graphql_name }
1155
+ end
1156
+ else
1157
+ stored_possible_types
1158
+ end
1159
+ visible_possible_types ||
1023
1160
  introspection_system.possible_types[type.graphql_name] ||
1024
1161
  (
1025
1162
  superclass.respond_to?(:possible_types) ?
@@ -1049,6 +1186,14 @@ module GraphQL
1049
1186
  end
1050
1187
  end
1051
1188
 
1189
+ # @api private
1190
+ # @see GraphQL::Dataloader
1191
+ def dataloader_class
1192
+ @dataloader_class || GraphQL::Dataloader::NullDataloader
1193
+ end
1194
+
1195
+ attr_writer :dataloader_class
1196
+
1052
1197
  def references_to(to_type = nil, from: nil)
1053
1198
  @own_references_to ||= Hash.new { |h, k| h[k] = [] }
1054
1199
  if to_type
@@ -1081,19 +1226,19 @@ module GraphQL
1081
1226
  GraphQL::Schema::TypeExpression.build_type(type_owner, ast_node)
1082
1227
  end
1083
1228
 
1084
- def get_field(type_or_name, field_name)
1229
+ def get_field(type_or_name, field_name, context = GraphQL::Query::NullContext)
1085
1230
  parent_type = case type_or_name
1086
1231
  when LateBoundType
1087
- get_type(type_or_name.name)
1232
+ get_type(type_or_name.name, context)
1088
1233
  when String
1089
- get_type(type_or_name)
1234
+ get_type(type_or_name, context)
1090
1235
  when Module
1091
1236
  type_or_name
1092
1237
  else
1093
1238
  raise ArgumentError, "unexpected field owner for #{field_name.inspect}: #{type_or_name.inspect} (#{type_or_name.class})"
1094
1239
  end
1095
1240
 
1096
- if parent_type.kind.fields? && (field = parent_type.get_field(field_name))
1241
+ if parent_type.kind.fields? && (field = parent_type.get_field(field_name, context))
1097
1242
  field
1098
1243
  elsif parent_type == query && (entry_point_field = introspection_system.entry_point(name: field_name))
1099
1244
  entry_point_field
@@ -1104,8 +1249,8 @@ module GraphQL
1104
1249
  end
1105
1250
  end
1106
1251
 
1107
- def get_fields(type)
1108
- type.fields
1252
+ def get_fields(type, context = GraphQL::Query::NullContext)
1253
+ type.fields(context)
1109
1254
  end
1110
1255
 
1111
1256
  def introspection(new_introspection_namespace = nil)
@@ -1165,6 +1310,47 @@ module GraphQL
1165
1310
  end
1166
1311
  end
1167
1312
 
1313
+ attr_writer :validate_timeout
1314
+
1315
+ def validate_timeout(new_validate_timeout = nil)
1316
+ if new_validate_timeout
1317
+ @validate_timeout = new_validate_timeout
1318
+ elsif defined?(@validate_timeout)
1319
+ @validate_timeout
1320
+ else
1321
+ find_inherited_value(:validate_timeout)
1322
+ end
1323
+ end
1324
+
1325
+ # Validate a query string according to this schema.
1326
+ # @param string_or_document [String, GraphQL::Language::Nodes::Document]
1327
+ # @return [Array<GraphQL::StaticValidation::Error >]
1328
+ def validate(string_or_document, rules: nil, context: nil)
1329
+ doc = if string_or_document.is_a?(String)
1330
+ GraphQL.parse(string_or_document)
1331
+ else
1332
+ string_or_document
1333
+ end
1334
+ query = GraphQL::Query.new(self, document: doc, context: context)
1335
+ validator_opts = { schema: self }
1336
+ rules && (validator_opts[:rules] = rules)
1337
+ validator = GraphQL::StaticValidation::Validator.new(**validator_opts)
1338
+ res = validator.validate(query, timeout: validate_timeout, max_errors: validate_max_errors)
1339
+ res[:errors]
1340
+ end
1341
+
1342
+ attr_writer :validate_max_errors
1343
+
1344
+ def validate_max_errors(new_validate_max_errors = nil)
1345
+ if new_validate_max_errors
1346
+ @validate_max_errors = new_validate_max_errors
1347
+ elsif defined?(@validate_max_errors)
1348
+ @validate_max_errors
1349
+ else
1350
+ find_inherited_value(:validate_max_errors)
1351
+ end
1352
+ end
1353
+
1168
1354
  attr_writer :max_complexity
1169
1355
 
1170
1356
  def max_complexity(max_complexity = nil)
@@ -1180,7 +1366,7 @@ module GraphQL
1180
1366
  attr_writer :analysis_engine
1181
1367
 
1182
1368
  def analysis_engine
1183
- @analysis_engine || find_inherited_value(:analysis_engine, GraphQL::Analysis)
1369
+ @analysis_engine || find_inherited_value(:analysis_engine, self.default_analysis_engine)
1184
1370
  end
1185
1371
 
1186
1372
  def using_ast_analysis?
@@ -1188,11 +1374,9 @@ module GraphQL
1188
1374
  end
1189
1375
 
1190
1376
  def interpreter?
1191
- if defined?(@interpreter)
1192
- @interpreter
1193
- else
1194
- find_inherited_value(:interpreter?, false)
1195
- end
1377
+ query_execution_strategy == GraphQL::Execution::Interpreter &&
1378
+ mutation_execution_strategy == GraphQL::Execution::Interpreter &&
1379
+ subscription_execution_strategy == GraphQL::Execution::Interpreter
1196
1380
  end
1197
1381
 
1198
1382
  attr_writer :interpreter
@@ -1265,7 +1449,6 @@ module GraphQL
1265
1449
  if new_orphan_types.any?
1266
1450
  new_orphan_types = new_orphan_types.flatten
1267
1451
  add_type_and_traverse(new_orphan_types, root: false)
1268
- @orphan_types = new_orphan_types
1269
1452
  own_orphan_types.concat(new_orphan_types.flatten)
1270
1453
  end
1271
1454
 
@@ -1276,7 +1459,15 @@ module GraphQL
1276
1459
  if superclass <= GraphQL::Schema
1277
1460
  superclass.default_execution_strategy
1278
1461
  else
1279
- @default_execution_strategy ||= GraphQL::Execution::Execute
1462
+ @default_execution_strategy ||= GraphQL::Execution::Interpreter
1463
+ end
1464
+ end
1465
+
1466
+ def default_analysis_engine
1467
+ if superclass <= GraphQL::Schema
1468
+ superclass.default_analysis_engine
1469
+ else
1470
+ @default_analysis_engine ||= GraphQL::Analysis::AST
1280
1471
  end
1281
1472
  end
1282
1473
 
@@ -1290,14 +1481,14 @@ module GraphQL
1290
1481
 
1291
1482
  def rescue_from(*err_classes, &handler_block)
1292
1483
  err_classes.each do |err_class|
1293
- own_rescues[err_class] = handler_block
1484
+ error_handler.rescue_from(err_class, handler_block)
1294
1485
  end
1295
1486
  end
1296
1487
 
1297
1488
  # rubocop:disable Lint/DuplicateMethods
1298
1489
  module ResolveTypeWithType
1299
1490
  def resolve_type(type, obj, ctx)
1300
- first_resolved_type = if type.is_a?(Module) && type.respond_to?(:resolve_type)
1491
+ first_resolved_type, resolved_value = if type.is_a?(Module) && type.respond_to?(:resolve_type)
1301
1492
  type.resolve_type(obj, ctx)
1302
1493
  else
1303
1494
  super
@@ -1305,7 +1496,11 @@ module GraphQL
1305
1496
 
1306
1497
  after_lazy(first_resolved_type) do |resolved_type|
1307
1498
  if resolved_type.nil? || (resolved_type.is_a?(Module) && resolved_type.respond_to?(:kind)) || resolved_type.is_a?(GraphQL::BaseType)
1308
- resolved_type
1499
+ if resolved_value
1500
+ [resolved_type, resolved_value]
1501
+ else
1502
+ resolved_type
1503
+ end
1309
1504
  else
1310
1505
  raise ".resolve_type should return a type definition, but got #{resolved_type.inspect} (#{resolved_type.class}) from `resolve_type(#{type}, #{obj}, #{ctx})`"
1311
1506
  end
@@ -1330,10 +1525,6 @@ module GraphQL
1330
1525
  super
1331
1526
  end
1332
1527
 
1333
- def rescues
1334
- find_inherited_value(:rescues, EMPTY_HASH).merge(own_rescues)
1335
- end
1336
-
1337
1528
  def object_from_id(node_id, ctx)
1338
1529
  raise GraphQL::RequiredImplementationMissingError, "#{self.name}.object_from_id(node_id, ctx) must be implemented to load by ID (tried to load from id `#{node_id}`)"
1339
1530
  end
@@ -1410,11 +1601,10 @@ module GraphQL
1410
1601
  def parse_error(parse_err, ctx)
1411
1602
  ctx.errors.push(parse_err)
1412
1603
  end
1413
- attr_writer :error_handler
1414
1604
 
1415
- # @return [GraphQL::Execution::Errors, Class<GraphQL::Execution::Errors::NullErrorHandler>]
1605
+ # @return [GraphQL::Execution::Errors]
1416
1606
  def error_handler
1417
- @error_handler ||= GraphQL::Execution::Errors::NullErrorHandler
1607
+ @error_handler ||= GraphQL::Execution::Errors.new(self)
1418
1608
  end
1419
1609
 
1420
1610
  def lazy_resolve(lazy_class, value_method)
@@ -1422,6 +1612,10 @@ module GraphQL
1422
1612
  end
1423
1613
 
1424
1614
  def instrument(instrument_step, instrumenter, options = {})
1615
+ if instrument_step == :field
1616
+ GraphQL::Deprecation.warn "Field instrumentation (#{instrumenter.inspect}) will be removed in GraphQL-Ruby 2.0, please upgrade to field extensions: https://graphql-ruby.org/type_definitions/field_extensions.html"
1617
+ end
1618
+
1425
1619
  step = if instrument_step == :field && options[:after_built_ins]
1426
1620
  :field_after_built_ins
1427
1621
  else
@@ -1433,9 +1627,9 @@ module GraphQL
1433
1627
 
1434
1628
  # Add several directives at once
1435
1629
  # @param new_directives [Class]
1436
- def directives(new_directives = nil)
1437
- if new_directives
1438
- new_directives.each { |d| directive(d) }
1630
+ def directives(*new_directives)
1631
+ if new_directives.any?
1632
+ new_directives.flatten.each { |d| directive(d) }
1439
1633
  end
1440
1634
 
1441
1635
  find_inherited_value(:directives, default_directives).merge(own_directives)
@@ -1443,17 +1637,17 @@ module GraphQL
1443
1637
 
1444
1638
  # Attach a single directive to this schema
1445
1639
  # @param new_directive [Class]
1640
+ # @return void
1446
1641
  def directive(new_directive)
1447
1642
  add_type_and_traverse(new_directive, root: false)
1448
- own_directives[new_directive.graphql_name] = new_directive
1449
1643
  end
1450
1644
 
1451
1645
  def default_directives
1452
- {
1646
+ @default_directives ||= {
1453
1647
  "include" => GraphQL::Schema::Directive::Include,
1454
1648
  "skip" => GraphQL::Schema::Directive::Skip,
1455
1649
  "deprecated" => GraphQL::Schema::Directive::Deprecated,
1456
- }
1650
+ }.freeze
1457
1651
  end
1458
1652
 
1459
1653
  def tracer(new_tracer)
@@ -1466,7 +1660,7 @@ module GraphQL
1466
1660
 
1467
1661
  def query_analyzer(new_analyzer)
1468
1662
  if new_analyzer == GraphQL::Authorization::Analyzer
1469
- warn("The Authorization query analyzer is deprecated. Authorizing at query runtime is generally a better idea.")
1663
+ GraphQL::Deprecation.warn("The Authorization query analyzer is deprecated. Authorizing at query runtime is generally a better idea.")
1470
1664
  end
1471
1665
  own_query_analyzers << new_analyzer
1472
1666
  end
@@ -1477,6 +1671,7 @@ module GraphQL
1477
1671
 
1478
1672
  def middleware(new_middleware = nil)
1479
1673
  if new_middleware
1674
+ GraphQL::Deprecation.warn "Middleware will be removed in GraphQL-Ruby 2.0, please upgrade to Field Extensions: https://graphql-ruby.org/type_definitions/field_extensions.html"
1480
1675
  own_middleware << new_middleware
1481
1676
  else
1482
1677
  # TODO make sure this is cached when running a query
@@ -1492,6 +1687,14 @@ module GraphQL
1492
1687
  find_inherited_value(:multiplex_analyzers, EMPTY_ARRAY) + own_multiplex_analyzers
1493
1688
  end
1494
1689
 
1690
+ def sanitized_printer(new_sanitized_printer = nil)
1691
+ if new_sanitized_printer
1692
+ @own_sanitized_printer = new_sanitized_printer
1693
+ else
1694
+ @own_sanitized_printer || GraphQL::Language::SanitizedPrinter
1695
+ end
1696
+ end
1697
+
1495
1698
  # Execute a query on itself.
1496
1699
  # @see {Query#initialize} for arguments.
1497
1700
  # @return [Hash] query result, ready to be serialized as JSON
@@ -1548,49 +1751,78 @@ module GraphQL
1548
1751
  end
1549
1752
  end
1550
1753
 
1551
- # Call the given block at the right time, either:
1552
- # - Right away, if `value` is not registered with `lazy_resolve`
1553
- # - After resolving `value`, if it's registered with `lazy_resolve` (eg, `Promise`)
1554
1754
  # @api private
1555
- def after_lazy(value)
1556
- if lazy?(value)
1557
- GraphQL::Execution::Lazy.new do
1558
- result = sync_lazy(value)
1559
- # The returned result might also be lazy, so check it, too
1560
- after_lazy(result) do |final_result|
1561
- yield(final_result) if block_given?
1755
+ def add_subscription_extension_if_necessary
1756
+ if interpreter? && !defined?(@subscription_extension_added) && subscription && self.subscriptions
1757
+ @subscription_extension_added = true
1758
+ if subscription.singleton_class.ancestors.include?(Subscriptions::SubscriptionRoot)
1759
+ GraphQL::Deprecation.warn("`extend Subscriptions::SubscriptionRoot` is no longer required; you may remove it from #{self}'s `subscription` root type (#{subscription}).")
1760
+ else
1761
+ subscription.all_field_definitions.each do |field|
1762
+ field.extension(Subscriptions::DefaultSubscriptionResolveExtension)
1562
1763
  end
1563
1764
  end
1564
- else
1565
- yield(value) if block_given?
1566
1765
  end
1567
1766
  end
1568
1767
 
1569
- # Override this method to handle lazy objects in a custom way.
1570
- # @param value [Object] an instance of a class registered with {.lazy_resolve}
1571
- # @param ctx [GraphQL::Query::Context] the context for this query
1572
- # @return [Object] A GraphQL-ready (non-lazy) object
1573
- def sync_lazy(value)
1574
- lazy_method = lazy_method_name(value)
1575
- if lazy_method
1576
- synced_value = value.public_send(lazy_method)
1577
- sync_lazy(synced_value)
1578
- else
1579
- value
1580
- end
1768
+ def query_stack_error(query, err)
1769
+ query.context.errors.push(GraphQL::ExecutionError.new("This query is too large to execute."))
1581
1770
  end
1582
1771
 
1583
- # @return [Symbol, nil] The method name to lazily resolve `obj`, or nil if `obj`'s class wasn't registered wtih {#lazy_resolve}.
1584
- def lazy_method_name(obj)
1585
- lazy_methods.get(obj)
1586
- end
1772
+ private
1587
1773
 
1588
- # @return [Boolean] True if this object should be lazily resolved
1589
- def lazy?(obj)
1590
- !!lazy_method_name(obj)
1591
- end
1774
+ # @param t [Module, Array<Module>]
1775
+ # @return [void]
1776
+ def add_type_and_traverse(t, root:)
1777
+ if root
1778
+ @root_types ||= []
1779
+ @root_types << t
1780
+ end
1781
+ new_types = Array(t)
1782
+ addition = Schema::Addition.new(schema: self, own_types: own_types, new_types: new_types)
1783
+ addition.types.each do |name, types_entry| # rubocop:disable Development/ContextIsPassedCop -- build-time, not query-time
1784
+ if (prev_entry = own_types[name])
1785
+ prev_entries = case prev_entry
1786
+ when Array
1787
+ prev_entry
1788
+ when Module
1789
+ own_types[name] = [prev_entry]
1790
+ else
1791
+ raise "Invariant: unexpected prev_entry at #{name.inspect} when adding #{t.inspect}"
1792
+ end
1592
1793
 
1593
- private
1794
+ case types_entry
1795
+ when Array
1796
+ prev_entries.concat(types_entry)
1797
+ prev_entries.uniq! # in case any are being re-visited
1798
+ when Module
1799
+ if !prev_entries.include?(types_entry)
1800
+ prev_entries << types_entry
1801
+ end
1802
+ else
1803
+ raise "Invariant: unexpected types_entry at #{name} when adding #{t.inspect}"
1804
+ end
1805
+ else
1806
+ if types_entry.is_a?(Array)
1807
+ types_entry.uniq!
1808
+ end
1809
+ own_types[name] = types_entry
1810
+ end
1811
+ end
1812
+
1813
+ own_possible_types.merge!(addition.possible_types) { |key, old_val, new_val| old_val + new_val }
1814
+ own_union_memberships.merge!(addition.union_memberships)
1815
+
1816
+ addition.references.each { |thing, pointers|
1817
+ pointers.each { |pointer| references_to(thing, from: pointer) }
1818
+ }
1819
+
1820
+ addition.directives.each { |dir_class| own_directives[dir_class.graphql_name] = dir_class }
1821
+
1822
+ addition.arguments_with_default_values.each do |arg|
1823
+ arg.validate_default_value
1824
+ end
1825
+ end
1594
1826
 
1595
1827
  def lazy_methods
1596
1828
  if !defined?(@lazy_methods)
@@ -1600,6 +1832,7 @@ module GraphQL
1600
1832
  else
1601
1833
  @lazy_methods = GraphQL::Execution::Lazy::LazyMethodMap.new
1602
1834
  @lazy_methods.set(GraphQL::Execution::Lazy, :value)
1835
+ @lazy_methods.set(GraphQL::Dataloader::Request, :load)
1603
1836
  end
1604
1837
  end
1605
1838
  @lazy_methods
@@ -1617,10 +1850,6 @@ module GraphQL
1617
1850
  @own_plugins ||= []
1618
1851
  end
1619
1852
 
1620
- def own_rescues
1621
- @own_rescues ||= {}
1622
- end
1623
-
1624
1853
  def own_orphan_types
1625
1854
  @own_orphan_types ||= []
1626
1855
  end
@@ -1660,209 +1889,14 @@ module GraphQL
1660
1889
  def own_multiplex_analyzers
1661
1890
  @own_multiplex_analyzers ||= []
1662
1891
  end
1663
-
1664
- # @param t [Module, Array<Module>]
1665
- # @return [void]
1666
- def add_type_and_traverse(t, root:)
1667
- if root
1668
- @root_types ||= []
1669
- @root_types << t
1670
- end
1671
- late_types = []
1672
- new_types = Array(t)
1673
- new_types.each { |t| add_type(t, owner: nil, late_types: late_types) }
1674
- missed_late_types = 0
1675
- while (late_type_vals = late_types.shift)
1676
- type_owner, lt = late_type_vals
1677
- if lt.is_a?(String)
1678
- type = Member::BuildType.constantize(lt)
1679
- # Reset the counter, since we might succeed next go-round
1680
- missed_late_types = 0
1681
- update_type_owner(type_owner, type)
1682
- add_type(type, owner: type_owner, late_types: late_types)
1683
- elsif lt.is_a?(LateBoundType)
1684
- if (type = get_type(lt.graphql_name))
1685
- # Reset the counter, since we might succeed next go-round
1686
- missed_late_types = 0
1687
- update_type_owner(type_owner, type)
1688
- add_type(type, owner: type_owner, late_types: late_types)
1689
- else
1690
- missed_late_types += 1
1691
- # Add it back to the list, maybe we'll be able to resolve it later.
1692
- late_types << [type_owner, lt]
1693
- if missed_late_types == late_types.size
1694
- # We've looked at all of them and haven't resolved one.
1695
- raise UnresolvedLateBoundTypeError.new(type: lt)
1696
- else
1697
- # Try the next one
1698
- end
1699
- end
1700
- else
1701
- raise ArgumentError, "Unexpected late type: #{lt.inspect}"
1702
- end
1703
- end
1704
- nil
1705
- end
1706
-
1707
- def update_type_owner(owner, type)
1708
- case owner
1709
- when Class
1710
- if owner.kind.union?
1711
- # It's a union with possible_types
1712
- # Replace the item by class name
1713
- owner.type_memberships.each { |tm|
1714
- possible_type = tm.object_type
1715
- if possible_type.is_a?(String) && (possible_type == type.name)
1716
- # This is a match of Ruby class names, not graphql names,
1717
- # since strings are used to refer to constants.
1718
- tm.object_type = type
1719
- elsif possible_type.is_a?(LateBoundType) && possible_type.graphql_name == type.graphql_name
1720
- tm.object_type = type
1721
- end
1722
- }
1723
- own_possible_types[owner.graphql_name] = owner.possible_types
1724
- elsif type.kind.interface? && owner.kind.object?
1725
- new_interfaces = owner.interfaces.map do |t|
1726
- if t.is_a?(String) && t == type.graphql_name
1727
- type
1728
- elsif t.is_a?(LateBoundType) && t.graphql_name == type.graphql_name
1729
- type
1730
- else
1731
- t
1732
- end
1733
- end
1734
- owner.implements(*new_interfaces)
1735
- end
1736
-
1737
- when nil
1738
- # It's a root type
1739
- own_types[type.graphql_name] = type
1740
- when GraphQL::Schema::Field, GraphQL::Schema::Argument
1741
- orig_type = owner.type
1742
- # Apply list/non-null wrapper as needed
1743
- if orig_type.respond_to?(:of_type)
1744
- transforms = []
1745
- while (orig_type.respond_to?(:of_type))
1746
- if orig_type.kind.non_null?
1747
- transforms << :to_non_null_type
1748
- elsif orig_type.kind.list?
1749
- transforms << :to_list_type
1750
- else
1751
- raise "Invariant: :of_type isn't non-null or list"
1752
- end
1753
- orig_type = orig_type.of_type
1754
- end
1755
- transforms.reverse_each { |t| type = type.public_send(t) }
1756
- end
1757
- owner.type = type
1758
- else
1759
- raise "Unexpected update: #{owner.inspect} #{type.inspect}"
1760
- end
1761
- end
1762
-
1763
- def add_type(type, owner:, late_types:)
1764
- if type.respond_to?(:metadata) && type.metadata.is_a?(Hash)
1765
- type_class = type.metadata[:type_class]
1766
- if type_class.nil?
1767
- raise ArgumentError, "Can't add legacy type: #{type} (#{type.class})"
1768
- else
1769
- type = type_class
1770
- end
1771
- elsif type.is_a?(String) || type.is_a?(GraphQL::Schema::LateBoundType)
1772
- late_types << [owner, type]
1773
- return
1774
- end
1775
-
1776
- if owner.is_a?(Class) && owner < GraphQL::Schema::Union
1777
- um = own_union_memberships[type.graphql_name] ||= []
1778
- um << owner
1779
- end
1780
-
1781
- if (prev_type = own_types[type.graphql_name])
1782
- if prev_type != type
1783
- raise ArgumentError, "Conflicting type definitions for `#{type.graphql_name}`: #{prev_type} (#{prev_type.class}), #{type} #{type.class}"
1784
- else
1785
- # This type was already added
1786
- end
1787
- elsif type.is_a?(Class) && type < GraphQL::Schema::Directive
1788
- type.arguments.each do |_name, arg|
1789
- arg_type = arg.type.unwrap
1790
- references_to(arg_type, from: arg)
1791
- add_type(arg_type, owner: arg, late_types: late_types)
1792
- end
1793
- else
1794
- own_types[type.graphql_name] = type
1795
- if type.kind.fields?
1796
- type.fields.each do |_name, field|
1797
- field_type = field.type.unwrap
1798
- references_to(field_type, from: field)
1799
- add_type(field_type, owner: field, late_types: late_types)
1800
- field.arguments.each do |_name, arg|
1801
- arg_type = arg.type.unwrap
1802
- references_to(arg_type, from: arg)
1803
- add_type(arg_type, owner: arg, late_types: late_types)
1804
- end
1805
- end
1806
- end
1807
- if type.kind.input_object?
1808
- type.arguments.each do |_name, arg|
1809
- arg_type = arg.type.unwrap
1810
- references_to(arg_type, from: arg)
1811
- add_type(arg_type, owner: arg, late_types: late_types)
1812
- end
1813
- end
1814
- if type.kind.union?
1815
- own_possible_types[type.graphql_name] = type.possible_types
1816
- type.possible_types.each do |t|
1817
- add_type(t, owner: type, late_types: late_types)
1818
- end
1819
- end
1820
- if type.kind.interface?
1821
- type.orphan_types.each do |t|
1822
- add_type(t, owner: type, late_types: late_types)
1823
- end
1824
- end
1825
- if type.kind.object?
1826
- own_possible_types[type.graphql_name] = [type]
1827
- type.interfaces.each do |i|
1828
- implementers = own_possible_types[i.graphql_name] ||= []
1829
- implementers << type
1830
- add_type(i, owner: type, late_types: late_types)
1831
- end
1832
- end
1833
- end
1834
- end
1835
1892
  end
1836
1893
 
1837
- # Call the given block at the right time, either:
1838
- # - Right away, if `value` is not registered with `lazy_resolve`
1839
- # - After resolving `value`, if it's registered with `lazy_resolve` (eg, `Promise`)
1840
- # @api private
1841
- def after_lazy(value)
1842
- if lazy?(value)
1843
- GraphQL::Execution::Lazy.new do
1844
- result = sync_lazy(value)
1845
- # The returned result might also be lazy, so check it, too
1846
- after_lazy(result) do |final_result|
1847
- yield(final_result) if block_given?
1848
- end
1849
- end
1850
- else
1851
- yield(value) if block_given?
1852
- end
1894
+ def dataloader_class
1895
+ self.class.dataloader_class
1853
1896
  end
1854
1897
 
1855
- # @see Schema.sync_lazy for a hook to override
1856
- # @api private
1857
- def sync_lazy(value)
1858
- lazy_method = lazy_method_name(value)
1859
- if lazy_method
1860
- synced_value = value.public_send(lazy_method)
1861
- sync_lazy(synced_value)
1862
- else
1863
- value
1864
- end
1865
- end
1898
+ # Install these here so that subclasses will also install it.
1899
+ use(GraphQL::Pagination::Connections)
1866
1900
 
1867
1901
  protected
1868
1902