graphql 1.13.14 → 2.0.19

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 (261) hide show
  1. checksums.yaml +4 -4
  2. data/lib/generators/graphql/install_generator.rb +1 -1
  3. data/lib/generators/graphql/relay.rb +3 -17
  4. data/lib/generators/graphql/templates/schema.erb +3 -0
  5. data/lib/graphql/analysis/ast/field_usage.rb +3 -1
  6. data/lib/graphql/analysis/ast/max_query_complexity.rb +0 -1
  7. data/lib/graphql/analysis/ast/query_complexity.rb +1 -1
  8. data/lib/graphql/analysis/ast/query_depth.rb +0 -1
  9. data/lib/graphql/analysis/ast/visitor.rb +43 -36
  10. data/lib/graphql/analysis/ast.rb +2 -12
  11. data/lib/graphql/analysis.rb +0 -7
  12. data/lib/graphql/backtrace/table.rb +2 -20
  13. data/lib/graphql/backtrace/tracer.rb +2 -3
  14. data/lib/graphql/backtrace.rb +2 -8
  15. data/lib/graphql/dataloader/null_dataloader.rb +3 -1
  16. data/lib/graphql/dataloader/source.rb +9 -0
  17. data/lib/graphql/dataloader.rb +4 -1
  18. data/lib/graphql/dig.rb +1 -1
  19. data/lib/graphql/execution/errors.rb +12 -82
  20. data/lib/graphql/execution/interpreter/resolve.rb +26 -0
  21. data/lib/graphql/execution/interpreter/runtime.rb +163 -120
  22. data/lib/graphql/execution/interpreter.rb +187 -78
  23. data/lib/graphql/execution/lazy.rb +7 -21
  24. data/lib/graphql/execution/lookahead.rb +44 -40
  25. data/lib/graphql/execution/multiplex.rb +3 -174
  26. data/lib/graphql/execution.rb +11 -4
  27. data/lib/graphql/introspection/directive_type.rb +2 -2
  28. data/lib/graphql/introspection/dynamic_fields.rb +3 -8
  29. data/lib/graphql/introspection/entry_points.rb +2 -15
  30. data/lib/graphql/introspection/field_type.rb +1 -1
  31. data/lib/graphql/introspection/schema_type.rb +2 -2
  32. data/lib/graphql/introspection/type_type.rb +13 -6
  33. data/lib/graphql/introspection.rb +4 -3
  34. data/lib/graphql/language/document_from_schema_definition.rb +18 -35
  35. data/lib/graphql/language/lexer.rb +216 -1488
  36. data/lib/graphql/language/lexer.ri +744 -0
  37. data/lib/graphql/language/nodes.rb +41 -33
  38. data/lib/graphql/language/parser.rb +375 -363
  39. data/lib/graphql/language/parser.y +48 -43
  40. data/lib/graphql/language/printer.rb +37 -21
  41. data/lib/graphql/language/visitor.rb +191 -83
  42. data/lib/graphql/pagination/active_record_relation_connection.rb +0 -8
  43. data/lib/graphql/pagination/array_connection.rb +4 -2
  44. data/lib/graphql/pagination/connection.rb +31 -4
  45. data/lib/graphql/pagination/connections.rb +3 -28
  46. data/lib/graphql/pagination/relation_connection.rb +2 -0
  47. data/lib/graphql/query/context.rb +155 -196
  48. data/lib/graphql/query/input_validation_result.rb +10 -1
  49. data/lib/graphql/query/null_context.rb +0 -3
  50. data/lib/graphql/query/validation_pipeline.rb +12 -37
  51. data/lib/graphql/query/variable_validation_error.rb +2 -2
  52. data/lib/graphql/query/variables.rb +35 -21
  53. data/lib/graphql/query.rb +32 -43
  54. data/lib/graphql/railtie.rb +0 -104
  55. data/lib/graphql/rake_task/validate.rb +1 -1
  56. data/lib/graphql/rake_task.rb +29 -1
  57. data/lib/graphql/relay/range_add.rb +9 -20
  58. data/lib/graphql/relay.rb +0 -15
  59. data/lib/graphql/schema/addition.rb +7 -9
  60. data/lib/graphql/schema/argument.rb +36 -43
  61. data/lib/graphql/schema/build_from_definition.rb +32 -18
  62. data/lib/graphql/schema/directive/one_of.rb +12 -0
  63. data/lib/graphql/schema/directive/transform.rb +1 -1
  64. data/lib/graphql/schema/directive.rb +12 -23
  65. data/lib/graphql/schema/enum.rb +29 -41
  66. data/lib/graphql/schema/enum_value.rb +5 -25
  67. data/lib/graphql/schema/field/connection_extension.rb +4 -0
  68. data/lib/graphql/schema/field.rb +245 -343
  69. data/lib/graphql/schema/input_object.rb +57 -69
  70. data/lib/graphql/schema/interface.rb +0 -35
  71. data/lib/graphql/schema/introspection_system.rb +3 -8
  72. data/lib/graphql/schema/late_bound_type.rb +8 -2
  73. data/lib/graphql/schema/list.rb +18 -9
  74. data/lib/graphql/schema/loader.rb +1 -2
  75. data/lib/graphql/schema/member/base_dsl_methods.rb +15 -19
  76. data/lib/graphql/schema/member/build_type.rb +5 -7
  77. data/lib/graphql/schema/member/has_arguments.rb +146 -55
  78. data/lib/graphql/schema/member/has_deprecation_reason.rb +3 -4
  79. data/lib/graphql/schema/member/has_directives.rb +71 -56
  80. data/lib/graphql/schema/member/has_fields.rb +16 -4
  81. data/lib/graphql/schema/member/has_interfaces.rb +49 -10
  82. data/lib/graphql/schema/member/has_validators.rb +31 -5
  83. data/lib/graphql/schema/member/relay_shortcuts.rb +28 -2
  84. data/lib/graphql/schema/member/type_system_helpers.rb +17 -0
  85. data/lib/graphql/schema/member/validates_input.rb +3 -3
  86. data/lib/graphql/schema/member.rb +0 -6
  87. data/lib/graphql/schema/mutation.rb +0 -9
  88. data/lib/graphql/schema/non_null.rb +3 -9
  89. data/lib/graphql/schema/object.rb +15 -52
  90. data/lib/graphql/schema/relay_classic_mutation.rb +53 -42
  91. data/lib/graphql/schema/resolver/has_payload_type.rb +20 -10
  92. data/lib/graphql/schema/resolver.rb +41 -42
  93. data/lib/graphql/schema/scalar.rb +8 -23
  94. data/lib/graphql/schema/subscription.rb +0 -7
  95. data/lib/graphql/schema/timeout.rb +24 -28
  96. data/lib/graphql/schema/type_membership.rb +3 -0
  97. data/lib/graphql/schema/union.rb +10 -17
  98. data/lib/graphql/schema/warden.rb +34 -8
  99. data/lib/graphql/schema/wrapper.rb +0 -5
  100. data/lib/graphql/schema.rb +240 -968
  101. data/lib/graphql/static_validation/all_rules.rb +1 -0
  102. data/lib/graphql/static_validation/base_visitor.rb +4 -21
  103. data/lib/graphql/static_validation/definition_dependencies.rb +7 -1
  104. data/lib/graphql/static_validation/error.rb +2 -2
  105. data/lib/graphql/static_validation/literal_validator.rb +19 -1
  106. data/lib/graphql/static_validation/rules/directives_are_defined.rb +11 -5
  107. data/lib/graphql/static_validation/rules/directives_are_in_valid_locations.rb +12 -12
  108. data/lib/graphql/static_validation/rules/one_of_input_objects_are_valid.rb +66 -0
  109. data/lib/graphql/static_validation/rules/one_of_input_objects_are_valid_error.rb +29 -0
  110. data/lib/graphql/static_validation/rules/unique_directives_per_location.rb +12 -6
  111. data/lib/graphql/static_validation/rules/variable_default_values_are_correctly_typed.rb +1 -1
  112. data/lib/graphql/static_validation/validator.rb +3 -25
  113. data/lib/graphql/static_validation.rb +0 -2
  114. data/lib/graphql/subscriptions/action_cable_subscriptions.rb +7 -1
  115. data/lib/graphql/subscriptions/default_subscription_resolve_extension.rb +38 -1
  116. data/lib/graphql/subscriptions/event.rb +3 -8
  117. data/lib/graphql/subscriptions/instrumentation.rb +0 -51
  118. data/lib/graphql/subscriptions.rb +32 -20
  119. data/lib/graphql/tracing/active_support_notifications_trace.rb +16 -0
  120. data/lib/graphql/tracing/appoptics_trace.rb +231 -0
  121. data/lib/graphql/tracing/appsignal_trace.rb +66 -0
  122. data/lib/graphql/tracing/data_dog_trace.rb +148 -0
  123. data/lib/graphql/tracing/data_dog_tracing.rb +2 -0
  124. data/lib/graphql/tracing/new_relic_trace.rb +75 -0
  125. data/lib/graphql/tracing/notifications_trace.rb +41 -0
  126. data/lib/graphql/tracing/platform_trace.rb +107 -0
  127. data/lib/graphql/tracing/platform_tracing.rb +26 -40
  128. data/lib/graphql/tracing/prometheus_trace.rb +89 -0
  129. data/lib/graphql/tracing/prometheus_tracing.rb +3 -3
  130. data/lib/graphql/tracing/scout_trace.rb +72 -0
  131. data/lib/graphql/tracing/statsd_trace.rb +56 -0
  132. data/lib/graphql/tracing.rb +136 -41
  133. data/lib/graphql/type_kinds.rb +6 -3
  134. data/lib/graphql/types/iso_8601_date.rb +4 -1
  135. data/lib/graphql/types/iso_8601_date_time.rb +4 -0
  136. data/lib/graphql/types/relay/base_connection.rb +16 -6
  137. data/lib/graphql/types/relay/connection_behaviors.rb +5 -25
  138. data/lib/graphql/types/relay/default_relay.rb +5 -9
  139. data/lib/graphql/types/relay/edge_behaviors.rb +1 -4
  140. data/lib/graphql/types/relay/node_behaviors.rb +5 -1
  141. data/lib/graphql/types/relay.rb +0 -2
  142. data/lib/graphql/types/string.rb +1 -1
  143. data/lib/graphql/version.rb +1 -1
  144. data/lib/graphql.rb +11 -72
  145. metadata +31 -133
  146. data/lib/graphql/analysis/analyze_query.rb +0 -98
  147. data/lib/graphql/analysis/field_usage.rb +0 -45
  148. data/lib/graphql/analysis/max_query_complexity.rb +0 -26
  149. data/lib/graphql/analysis/max_query_depth.rb +0 -26
  150. data/lib/graphql/analysis/query_complexity.rb +0 -88
  151. data/lib/graphql/analysis/query_depth.rb +0 -43
  152. data/lib/graphql/analysis/reducer_state.rb +0 -48
  153. data/lib/graphql/argument.rb +0 -131
  154. data/lib/graphql/authorization.rb +0 -82
  155. data/lib/graphql/backtrace/legacy_tracer.rb +0 -56
  156. data/lib/graphql/backwards_compatibility.rb +0 -61
  157. data/lib/graphql/base_type.rb +0 -232
  158. data/lib/graphql/boolean_type.rb +0 -2
  159. data/lib/graphql/compatibility/execution_specification/counter_schema.rb +0 -53
  160. data/lib/graphql/compatibility/execution_specification/specification_schema.rb +0 -200
  161. data/lib/graphql/compatibility/execution_specification.rb +0 -436
  162. data/lib/graphql/compatibility/lazy_execution_specification/lazy_schema.rb +0 -111
  163. data/lib/graphql/compatibility/lazy_execution_specification.rb +0 -215
  164. data/lib/graphql/compatibility/query_parser_specification/parse_error_specification.rb +0 -87
  165. data/lib/graphql/compatibility/query_parser_specification/query_assertions.rb +0 -79
  166. data/lib/graphql/compatibility/query_parser_specification.rb +0 -266
  167. data/lib/graphql/compatibility/schema_parser_specification.rb +0 -682
  168. data/lib/graphql/compatibility.rb +0 -5
  169. data/lib/graphql/define/assign_argument.rb +0 -12
  170. data/lib/graphql/define/assign_connection.rb +0 -13
  171. data/lib/graphql/define/assign_enum_value.rb +0 -18
  172. data/lib/graphql/define/assign_global_id_field.rb +0 -11
  173. data/lib/graphql/define/assign_mutation_function.rb +0 -34
  174. data/lib/graphql/define/assign_object_field.rb +0 -42
  175. data/lib/graphql/define/defined_object_proxy.rb +0 -53
  176. data/lib/graphql/define/instance_definable.rb +0 -255
  177. data/lib/graphql/define/no_definition_error.rb +0 -7
  178. data/lib/graphql/define/non_null_with_bang.rb +0 -16
  179. data/lib/graphql/define/type_definer.rb +0 -31
  180. data/lib/graphql/define.rb +0 -31
  181. data/lib/graphql/deprecated_dsl.rb +0 -55
  182. data/lib/graphql/directive/deprecated_directive.rb +0 -2
  183. data/lib/graphql/directive/include_directive.rb +0 -2
  184. data/lib/graphql/directive/skip_directive.rb +0 -2
  185. data/lib/graphql/directive.rb +0 -107
  186. data/lib/graphql/enum_type.rb +0 -133
  187. data/lib/graphql/execution/execute.rb +0 -333
  188. data/lib/graphql/execution/flatten.rb +0 -40
  189. data/lib/graphql/execution/instrumentation.rb +0 -92
  190. data/lib/graphql/execution/lazy/resolve.rb +0 -91
  191. data/lib/graphql/execution/typecast.rb +0 -50
  192. data/lib/graphql/field/resolve.rb +0 -59
  193. data/lib/graphql/field.rb +0 -226
  194. data/lib/graphql/float_type.rb +0 -2
  195. data/lib/graphql/function.rb +0 -128
  196. data/lib/graphql/id_type.rb +0 -2
  197. data/lib/graphql/input_object_type.rb +0 -138
  198. data/lib/graphql/int_type.rb +0 -2
  199. data/lib/graphql/interface_type.rb +0 -72
  200. data/lib/graphql/internal_representation/document.rb +0 -27
  201. data/lib/graphql/internal_representation/node.rb +0 -206
  202. data/lib/graphql/internal_representation/print.rb +0 -51
  203. data/lib/graphql/internal_representation/rewrite.rb +0 -184
  204. data/lib/graphql/internal_representation/scope.rb +0 -88
  205. data/lib/graphql/internal_representation/visit.rb +0 -36
  206. data/lib/graphql/internal_representation.rb +0 -7
  207. data/lib/graphql/language/lexer.rl +0 -260
  208. data/lib/graphql/list_type.rb +0 -80
  209. data/lib/graphql/non_null_type.rb +0 -71
  210. data/lib/graphql/object_type.rb +0 -130
  211. data/lib/graphql/query/arguments.rb +0 -189
  212. data/lib/graphql/query/arguments_cache.rb +0 -24
  213. data/lib/graphql/query/executor.rb +0 -52
  214. data/lib/graphql/query/literal_input.rb +0 -136
  215. data/lib/graphql/query/serial_execution/field_resolution.rb +0 -92
  216. data/lib/graphql/query/serial_execution/operation_resolution.rb +0 -19
  217. data/lib/graphql/query/serial_execution/selection_resolution.rb +0 -23
  218. data/lib/graphql/query/serial_execution/value_resolution.rb +0 -87
  219. data/lib/graphql/query/serial_execution.rb +0 -40
  220. data/lib/graphql/relay/array_connection.rb +0 -83
  221. data/lib/graphql/relay/base_connection.rb +0 -189
  222. data/lib/graphql/relay/connection_instrumentation.rb +0 -54
  223. data/lib/graphql/relay/connection_resolve.rb +0 -43
  224. data/lib/graphql/relay/connection_type.rb +0 -54
  225. data/lib/graphql/relay/edge.rb +0 -27
  226. data/lib/graphql/relay/edge_type.rb +0 -19
  227. data/lib/graphql/relay/edges_instrumentation.rb +0 -39
  228. data/lib/graphql/relay/global_id_resolve.rb +0 -17
  229. data/lib/graphql/relay/mongo_relation_connection.rb +0 -50
  230. data/lib/graphql/relay/mutation/instrumentation.rb +0 -23
  231. data/lib/graphql/relay/mutation/resolve.rb +0 -56
  232. data/lib/graphql/relay/mutation/result.rb +0 -38
  233. data/lib/graphql/relay/mutation.rb +0 -106
  234. data/lib/graphql/relay/node.rb +0 -39
  235. data/lib/graphql/relay/page_info.rb +0 -7
  236. data/lib/graphql/relay/relation_connection.rb +0 -188
  237. data/lib/graphql/relay/type_extensions.rb +0 -32
  238. data/lib/graphql/scalar_type.rb +0 -91
  239. data/lib/graphql/schema/catchall_middleware.rb +0 -35
  240. data/lib/graphql/schema/default_parse_error.rb +0 -10
  241. data/lib/graphql/schema/default_type_error.rb +0 -17
  242. data/lib/graphql/schema/member/accepts_definition.rb +0 -164
  243. data/lib/graphql/schema/member/cached_graphql_definition.rb +0 -58
  244. data/lib/graphql/schema/member/instrumentation.rb +0 -131
  245. data/lib/graphql/schema/middleware_chain.rb +0 -82
  246. data/lib/graphql/schema/possible_types.rb +0 -44
  247. data/lib/graphql/schema/rescue_middleware.rb +0 -60
  248. data/lib/graphql/schema/timeout_middleware.rb +0 -88
  249. data/lib/graphql/schema/traversal.rb +0 -228
  250. data/lib/graphql/schema/validation.rb +0 -313
  251. data/lib/graphql/static_validation/default_visitor.rb +0 -15
  252. data/lib/graphql/static_validation/no_validate_visitor.rb +0 -10
  253. data/lib/graphql/string_type.rb +0 -2
  254. data/lib/graphql/subscriptions/subscription_root.rb +0 -76
  255. data/lib/graphql/tracing/opentelemetry_tracing.rb +0 -101
  256. data/lib/graphql/tracing/skylight_tracing.rb +0 -70
  257. data/lib/graphql/types/relay/node_field.rb +0 -24
  258. data/lib/graphql/types/relay/nodes_field.rb +0 -43
  259. data/lib/graphql/union_type.rb +0 -115
  260. data/lib/graphql/upgrader/member.rb +0 -937
  261. data/lib/graphql/upgrader/schema.rb +0 -38
@@ -1,24 +1,15 @@
1
1
  # frozen_string_literal: true
2
2
  require "graphql/schema/addition"
3
3
  require "graphql/schema/base_64_encoder"
4
- require "graphql/schema/catchall_middleware"
5
- require "graphql/schema/default_parse_error"
6
- require "graphql/schema/default_type_error"
7
4
  require "graphql/schema/find_inherited_value"
8
5
  require "graphql/schema/finder"
9
6
  require "graphql/schema/invalid_type_error"
10
7
  require "graphql/schema/introspection_system"
11
8
  require "graphql/schema/late_bound_type"
12
- require "graphql/schema/middleware_chain"
13
9
  require "graphql/schema/null_mask"
14
- require "graphql/schema/possible_types"
15
- require "graphql/schema/rescue_middleware"
16
10
  require "graphql/schema/timeout"
17
- require "graphql/schema/timeout_middleware"
18
- require "graphql/schema/traversal"
19
11
  require "graphql/schema/type_expression"
20
12
  require "graphql/schema/unique_within_type"
21
- require "graphql/schema/validation"
22
13
  require "graphql/schema/warden"
23
14
  require "graphql/schema/build_from_definition"
24
15
 
@@ -40,6 +31,7 @@ require "graphql/schema/union"
40
31
  require "graphql/schema/directive"
41
32
  require "graphql/schema/directive/deprecated"
42
33
  require "graphql/schema/directive/include"
34
+ require "graphql/schema/directive/one_of"
43
35
  require "graphql/schema/directive/skip"
44
36
  require "graphql/schema/directive/feature"
45
37
  require "graphql/schema/directive/flagged"
@@ -70,7 +62,7 @@ module GraphQL
70
62
  # Schemas can specify how queries should be executed against them.
71
63
  # `query_execution_strategy`, `mutation_execution_strategy` and `subscription_execution_strategy`
72
64
  # each apply to corresponding root types.
73
- # #
65
+ #
74
66
  # @example defining a schema
75
67
  # class MySchema < GraphQL::Schema
76
68
  # query QueryType
@@ -79,21 +71,19 @@ module GraphQL
79
71
  # end
80
72
  #
81
73
  class Schema
82
- extend Forwardable
83
- extend GraphQL::Schema::Member::AcceptsDefinition
84
74
  extend GraphQL::Schema::Member::HasAstNode
85
- include GraphQL::Define::InstanceDefinable
86
- extend GraphQL::Define::InstanceDefinable::DeprecatedDefine
87
75
  extend GraphQL::Schema::FindInheritedValue
88
76
 
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(".")}")
77
+ class DuplicateNamesError < GraphQL::Error
78
+ attr_reader :duplicated_name
79
+ def initialize(duplicated_name:, duplicated_definition_1:, duplicated_definition_2:)
80
+ @duplicated_name = duplicated_name
81
+ super(
82
+ "Found two visible definitions for `#{duplicated_name}`: #{duplicated_definition_1}, #{duplicated_definition_2}"
83
+ )
92
84
  end
93
85
  end
94
86
 
95
- class DuplicateNamesError < GraphQL::Error; end
96
-
97
87
  class UnresolvedLateBoundTypeError < GraphQL::Error
98
88
  attr_reader :type
99
89
  def initialize(type:)
@@ -102,764 +92,70 @@ module GraphQL
102
92
  end
103
93
  end
104
94
 
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
-
164
- deprecated_accepts_definitions \
165
- :query_execution_strategy, :mutation_execution_strategy, :subscription_execution_strategy,
166
- :validate_timeout, :validate_max_errors, :max_depth, :max_complexity, :default_max_page_size,
167
- :orphan_types, :resolve_type, :type_error, :parse_error,
168
- :error_bubbling,
169
- :raise_definition_error,
170
- :object_from_id, :id_from_object,
171
- :default_mask,
172
- :cursor_encoder,
173
- # If these are given as classes, normalize them. Accept `nil` when building from string.
174
- query: ->(schema, t) { schema.query = t.respond_to?(:graphql_definition) ? t.graphql_definition : t },
175
- mutation: ->(schema, t) { schema.mutation = t.respond_to?(:graphql_definition) ? t.graphql_definition : t },
176
- subscription: ->(schema, t) { schema.subscription = t.respond_to?(:graphql_definition) ? t.graphql_definition : t },
177
- disable_introspection_entry_points: ->(schema) { schema.disable_introspection_entry_points = true },
178
- disable_schema_introspection_entry_point: ->(schema) { schema.disable_schema_introspection_entry_point = true },
179
- disable_type_introspection_entry_point: ->(schema) { schema.disable_type_introspection_entry_point = true },
180
- directives: ->(schema, directives) { schema.directives = directives.reduce({}) { |m, d| m[d.graphql_name] = d; m } },
181
- directive: ->(schema, directive) { schema.directives[directive.graphql_name] = directive },
182
- instrument: ->(schema, type, instrumenter, after_built_ins: false) {
183
- if type == :field && after_built_ins
184
- type = :field_after_built_ins
185
- end
186
- schema.instrumenters[type] << instrumenter
187
- },
188
- query_analyzer: ->(schema, analyzer) {
189
- if analyzer == GraphQL::Authorization::Analyzer
190
- GraphQL::Deprecation.warn("The Authorization query analyzer is deprecated. Authorizing at query runtime is generally a better idea.")
191
- end
192
- schema.query_analyzers << analyzer
193
- },
194
- multiplex_analyzer: ->(schema, analyzer) { schema.multiplex_analyzers << analyzer },
195
- middleware: ->(schema, middleware) { schema.middleware << middleware },
196
- lazy_resolve: ->(schema, lazy_class, lazy_value_method) { schema.lazy_methods.set(lazy_class, lazy_value_method) },
197
- rescue_from: ->(schema, err_class, &block) { schema.rescue_from(err_class, &block) },
198
- tracer: ->(schema, tracer) { schema.tracers.push(tracer) }
199
-
200
- ensure_defined :introspection_system
201
-
202
- attr_accessor \
203
- :query, :mutation, :subscription,
204
- :query_execution_strategy, :mutation_execution_strategy, :subscription_execution_strategy,
205
- :validate_timeout, :validate_max_errors, :max_depth, :max_complexity, :default_max_page_size,
206
- :orphan_types, :directives,
207
- :query_analyzers, :multiplex_analyzers, :instrumenters, :lazy_methods,
208
- :cursor_encoder,
209
- :ast_node,
210
- :raise_definition_error,
211
- :introspection_namespace,
212
- :analysis_engine
213
-
214
- # [Boolean] True if this object bubbles validation errors up from a field into its parent InputObject, if there is one.
215
- attr_accessor :error_bubbling
216
-
217
- # Single, long-lived instance of the provided subscriptions class, if there is one.
218
- # @return [GraphQL::Subscriptions]
219
- attr_accessor :subscriptions
220
-
221
- # @return [MiddlewareChain] MiddlewareChain which is applied to fields during execution
222
- attr_accessor :middleware
223
-
224
- # @return [<#call(member, ctx)>] A callable for filtering members of the schema
225
- # @see {Query.new} for query-specific filters with `except:`
226
- attr_accessor :default_mask
227
-
228
- # @see {GraphQL::Query::Context} The parent class of these classes
229
- # @return [Class] Instantiated for each query
230
- attr_accessor :context_class
231
-
232
- # [Boolean] True if this object disables the introspection entry point fields
233
- attr_accessor :disable_introspection_entry_points
234
-
235
- def disable_introspection_entry_points?
236
- !!@disable_introspection_entry_points
237
- end
238
-
239
- # [Boolean] True if this object disables the __schema introspection entry point field
240
- attr_accessor :disable_schema_introspection_entry_point
241
-
242
- def disable_schema_introspection_entry_point?
243
- !!@disable_schema_introspection_entry_point
244
- end
245
-
246
- # [Boolean] True if this object disables the __type introspection entry point field
247
- attr_accessor :disable_type_introspection_entry_point
248
-
249
- def disable_type_introspection_entry_point?
250
- !!@disable_type_introspection_entry_point
251
- end
95
+ # Error that is raised when [#Schema#from_definition] is passed an invalid schema definition string.
96
+ class InvalidDocumentError < Error; end;
252
97
 
253
98
  class << self
254
- attr_writer :default_execution_strategy
255
- end
256
-
257
- def default_filter
258
- GraphQL::Filter.new(except: default_mask)
259
- end
260
-
261
- # @return [Array<#trace(key, data)>] Tracers applied to every query
262
- # @see {Query#tracers} for query-specific tracers
263
- attr_reader :tracers
264
-
265
- DYNAMIC_FIELDS = ["__type", "__typename", "__schema"].freeze
266
-
267
- attr_reader :static_validator, :object_from_id_proc, :id_from_object_proc, :resolve_type_proc
268
-
269
- def initialize
270
- @tracers = []
271
- @definition_error = nil
272
- @orphan_types = []
273
- @directives = {}
274
- self.class.default_directives.each do |name, dir|
275
- @directives[name] = dir.graphql_definition
276
- end
277
- @static_validator = GraphQL::StaticValidation::Validator.new(schema: self)
278
- @middleware = MiddlewareChain.new(final_step: GraphQL::Execution::Execute::FieldResolveStep)
279
- @query_analyzers = []
280
- @multiplex_analyzers = []
281
- @resolve_type_proc = nil
282
- @object_from_id_proc = nil
283
- @id_from_object_proc = nil
284
- @type_error_proc = DefaultTypeError
285
- @parse_error_proc = DefaultParseError
286
- @instrumenters = Hash.new { |h, k| h[k] = [] }
287
- @lazy_methods = GraphQL::Execution::Lazy::LazyMethodMap.new
288
- @lazy_methods.set(GraphQL::Execution::Lazy, :value)
289
- @cursor_encoder = Base64Encoder
290
- # For schema instances, default to legacy runtime modules
291
- @analysis_engine = GraphQL::Analysis
292
- @query_execution_strategy = GraphQL::Execution::Execute
293
- @mutation_execution_strategy = GraphQL::Execution::Execute
294
- @subscription_execution_strategy = GraphQL::Execution::Execute
295
- @default_mask = GraphQL::Schema::NullMask
296
- @rebuilding_artifacts = false
297
- @context_class = GraphQL::Query::Context
298
- @introspection_namespace = nil
299
- @introspection_system = nil
300
- @interpreter = false
301
- @error_bubbling = false
302
- @disable_introspection_entry_points = false
303
- @disable_schema_introspection_entry_point = false
304
- @disable_type_introspection_entry_point = false
305
- end
306
-
307
- # @return [Boolean] True if using the new {GraphQL::Execution::Interpreter}
308
- def interpreter?
309
- query_execution_strategy == GraphQL::Execution::Interpreter &&
310
- mutation_execution_strategy == GraphQL::Execution::Interpreter &&
311
- subscription_execution_strategy == GraphQL::Execution::Interpreter
312
- end
313
-
314
- def inspect
315
- "#<#{self.class.name} ...>"
316
- end
317
-
318
- def initialize_copy(other)
319
- super
320
- @orphan_types = other.orphan_types.dup
321
- @directives = other.directives.dup
322
- @static_validator = GraphQL::StaticValidation::Validator.new(schema: self)
323
- @middleware = other.middleware.dup
324
- @query_analyzers = other.query_analyzers.dup
325
- @multiplex_analyzers = other.multiplex_analyzers.dup
326
- @tracers = other.tracers.dup
327
- @possible_types = GraphQL::Schema::PossibleTypes.new(self)
328
-
329
- @lazy_methods = other.lazy_methods.dup
330
-
331
- @instrumenters = Hash.new { |h, k| h[k] = [] }
332
- other.instrumenters.each do |key, insts|
333
- @instrumenters[key].concat(insts)
334
- end
335
-
336
- if other.rescues?
337
- @rescue_middleware = other.rescue_middleware
338
- end
339
-
340
- # This will be rebuilt when it's requested
341
- # or during a later `define` call
342
- @types = nil
343
- @introspection_system = nil
344
- end
345
-
346
- def rescue_from(*args, &block)
347
- rescue_middleware.rescue_from(*args, &block)
348
- end
349
-
350
- def remove_handler(*args, &block)
351
- rescue_middleware.remove_handler(*args, &block)
352
- end
353
-
354
- def using_ast_analysis?
355
- @analysis_engine == GraphQL::Analysis::AST
356
- end
357
-
358
- # For forwards-compatibility with Schema classes
359
- alias :graphql_definition :itself
360
-
361
- def deprecated_define(**kwargs, &block)
362
- super
363
- ensure_defined
364
- # Assert that all necessary configs are present:
365
- validation_error = Validation.validate(self)
366
- validation_error && raise(GraphQL::RequiredImplementationMissingError, validation_error)
367
- rebuild_artifacts
368
-
369
- @definition_error = nil
370
- nil
371
- rescue StandardError => err
372
- if @raise_definition_error || err.is_a?(CyclicalDefinitionError) || err.is_a?(GraphQL::RequiredImplementationMissingError)
373
- raise
374
- else
375
- # Raise this error _later_ to avoid messing with Rails constant loading
376
- @definition_error = err
377
- end
378
- nil
379
- end
380
-
381
- # Attach `instrumenter` to this schema for instrumenting events of `instrumentation_type`.
382
- # @param instrumentation_type [Symbol]
383
- # @param instrumenter
384
- # @return [void]
385
- def instrument(instrumentation_type, instrumenter)
386
- @instrumenters[instrumentation_type] << instrumenter
387
- if instrumentation_type == :field
388
- rebuild_artifacts
389
- end
390
- end
391
-
392
- # @return [Array<GraphQL::BaseType>] The root types of this schema
393
- def root_types
394
- @root_types ||= begin
395
- rebuild_artifacts
396
- @root_types
397
- end
398
- end
399
-
400
- # @see [GraphQL::Schema::Warden] Restricted access to members of a schema
401
- # @return [GraphQL::Schema::TypeMap] `{ name => type }` pairs of types in this schema
402
- def types
403
- @types ||= begin
404
- rebuild_artifacts
405
- @types
406
- end
407
- end
408
-
409
- def get_type(type_name)
410
- @types[type_name]
411
- end
412
-
413
- # @api private
414
- def introspection_system
415
- @introspection_system ||= begin
416
- rebuild_artifacts
417
- @introspection_system
418
- end
419
- end
420
-
421
- # Returns a list of Arguments and Fields referencing a certain type
422
- # @param type_name [String]
423
- # @return [Hash]
424
- def references_to(type_name = nil)
425
- rebuild_artifacts unless defined?(@type_reference_map)
426
- if type_name
427
- @type_reference_map.fetch(type_name, [])
428
- else
429
- @type_reference_map
430
- end
431
- end
432
-
433
- # Returns a list of Union types in which a type is a member
434
- # @param type [GraphQL::ObjectType]
435
- # @return [Array<GraphQL::UnionType>] list of union types of which the type is a member
436
- def union_memberships(type)
437
- rebuild_artifacts unless defined?(@union_memberships)
438
- @union_memberships.fetch(type.name, [])
439
- end
440
-
441
- # Execute a query on itself. Raises an error if the schema definition is invalid.
442
- # @see {Query#initialize} for arguments.
443
- # @return [Hash] query result, ready to be serialized as JSON
444
- def execute(query_str = nil, **kwargs)
445
- if query_str
446
- kwargs[:query] = query_str
447
- end
448
- # Some of the query context _should_ be passed to the multiplex, too
449
- multiplex_context = if (ctx = kwargs[:context])
450
- {
451
- backtrace: ctx[:backtrace],
452
- tracers: ctx[:tracers],
453
- }
454
- else
455
- {}
456
- end
457
- # Since we're running one query, don't run a multiplex-level complexity analyzer
458
- all_results = multiplex([kwargs], max_complexity: nil, context: multiplex_context)
459
- all_results[0]
460
- end
461
-
462
- # Execute several queries on itself. Raises an error if the schema definition is invalid.
463
- # @example Run several queries at once
464
- # context = { ... }
465
- # queries = [
466
- # { query: params[:query_1], variables: params[:variables_1], context: context },
467
- # { query: params[:query_2], variables: params[:variables_2], context: context },
468
- # ]
469
- # results = MySchema.multiplex(queries)
470
- # render json: {
471
- # result_1: results[0],
472
- # result_2: results[1],
473
- # }
474
- #
475
- # @see {Query#initialize} for query keyword arguments
476
- # @see {Execution::Multiplex#run_queries} for multiplex keyword arguments
477
- # @param queries [Array<Hash>] Keyword arguments for each query
478
- # @param context [Hash] Multiplex-level context
479
- # @return [Array<Hash>] One result for each query in the input
480
- def multiplex(queries, **kwargs)
481
- with_definition_error_check {
482
- GraphQL::Execution::Multiplex.run_all(self, queries, **kwargs)
483
- }
484
- end
485
-
486
- # Search for a schema member using a string path
487
- # @example Finding a Field
488
- # Schema.find("Ensemble.musicians")
489
- #
490
- # @see {GraphQL::Schema::Finder} for more examples
491
- # @param path [String] A dot-separated path to the member
492
- # @raise [Schema::Finder::MemberNotFoundError] if path could not be found
493
- # @return [GraphQL::BaseType, GraphQL::Field, GraphQL::Argument, GraphQL::Directive] A GraphQL Schema Member
494
- def find(path)
495
- rebuild_artifacts unless defined?(@finder)
496
- @find_cache[path] ||= @finder.find(path)
497
- end
498
-
499
- # Resolve field named `field_name` for type `parent_type`.
500
- # Handles dynamic fields `__typename`, `__type` and `__schema`, too
501
- # @param parent_type [String, GraphQL::BaseType]
502
- # @param field_name [String]
503
- # @return [GraphQL::Field, nil] The field named `field_name` on `parent_type`
504
- # @see [GraphQL::Schema::Warden] Restricted access to members of a schema
505
- def get_field(parent_type, field_name)
506
- with_definition_error_check do
507
- parent_type_name = case parent_type
508
- when GraphQL::BaseType, Class, Module
509
- parent_type.graphql_name
510
- when String
511
- parent_type
99
+ # Create schema with the result of an introspection query.
100
+ # @param introspection_result [Hash] A response from {GraphQL::Introspection::INTROSPECTION_QUERY}
101
+ # @return [Class<GraphQL::Schema>] the schema described by `input`
102
+ def from_introspection(introspection_result)
103
+ GraphQL::Schema::Loader.load(introspection_result)
104
+ end
105
+
106
+ # Create schema from an IDL schema or file containing an IDL definition.
107
+ # @param definition_or_path [String] A schema definition string, or a path to a file containing the definition
108
+ # @param default_resolve [<#call(type, field, obj, args, ctx)>] A callable for handling field resolution
109
+ # @param parser [Object] An object for handling definition string parsing (must respond to `parse`)
110
+ # @param using [Hash] Plugins to attach to the created schema with `use(key, value)`
111
+ # @return [Class] the schema described by `document`
112
+ def from_definition(definition_or_path, default_resolve: nil, parser: GraphQL.default_parser, using: {})
113
+ # If the file ends in `.graphql` or `.graphqls`, treat it like a filepath
114
+ if definition_or_path.end_with?(".graphql") || definition_or_path.end_with?(".graphqls")
115
+ GraphQL::Schema::BuildFromDefinition.from_definition_path(
116
+ self,
117
+ definition_or_path,
118
+ default_resolve: default_resolve,
119
+ parser: parser,
120
+ using: using,
121
+ )
512
122
  else
513
- raise "Unexpected parent_type: #{parent_type}"
514
- end
515
-
516
- defined_field = @instrumented_field_map[parent_type_name][field_name]
517
- if defined_field
518
- defined_field
519
- elsif parent_type == query && (entry_point_field = introspection_system.entry_point(name: field_name))
520
- entry_point_field
521
- elsif (dynamic_field = introspection_system.dynamic_field(name: field_name))
522
- dynamic_field
523
- else
524
- nil
123
+ GraphQL::Schema::BuildFromDefinition.from_definition(
124
+ self,
125
+ definition_or_path,
126
+ default_resolve: default_resolve,
127
+ parser: parser,
128
+ using: using,
129
+ )
525
130
  end
526
131
  end
527
- end
528
-
529
- # Fields for this type, after instrumentation is applied
530
- # @return [Hash<String, GraphQL::Field>]
531
- def get_fields(type)
532
- @instrumented_field_map[type.graphql_name]
533
- end
534
132
 
535
- def type_from_ast(ast_node, context:)
536
- GraphQL::Schema::TypeExpression.build_type(self, ast_node)
537
- end
538
-
539
- # @see [GraphQL::Schema::Warden] Restricted access to members of a schema
540
- # @param type_defn [GraphQL::InterfaceType, GraphQL::UnionType] the type whose members you want to retrieve
541
- # @param context [GraphQL::Query::Context] The context for the current query
542
- # @return [Array<GraphQL::ObjectType>] types which belong to `type_defn` in this schema
543
- def possible_types(type_defn, context = GraphQL::Query::NullContext)
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
555
- end
556
-
557
- # @see [GraphQL::Schema::Warden] Restricted access to root types
558
- # @return [GraphQL::ObjectType, nil]
559
- def root_type_for_operation(operation)
560
- case operation
561
- when "query"
562
- query
563
- when "mutation"
564
- mutation
565
- when "subscription"
566
- subscription
567
- else
568
- raise ArgumentError, "unknown operation type: #{operation}"
569
- end
570
- end
571
-
572
- def execution_strategy_for_operation(operation)
573
- case operation
574
- when "query"
575
- query_execution_strategy
576
- when "mutation"
577
- mutation_execution_strategy
578
- when "subscription"
579
- subscription_execution_strategy
580
- else
581
- raise ArgumentError, "unknown operation type: #{operation}"
582
- end
583
- end
584
-
585
- # Determine the GraphQL type for a given object.
586
- # This is required for unions and interfaces (including Relay's `Node` interface)
587
- # @see [GraphQL::Schema::Warden] Restricted access to members of a schema
588
- # @param type [GraphQL::UnionType, GraphQL:InterfaceType] the abstract type which is being resolved
589
- # @param object [Any] An application object which GraphQL is currently resolving on
590
- # @param ctx [GraphQL::Query::Context] The context for the current query
591
- # @return [GraphQL::ObjectType] The type for exposing `object` in GraphQL
592
- def resolve_type(type, object, ctx = :__undefined__)
593
- check_resolved_type(type, object, ctx) do |ok_type, ok_object, ok_ctx|
594
- if @resolve_type_proc.nil?
595
- raise(GraphQL::RequiredImplementationMissingError, "Can't determine GraphQL type for: #{ok_object.inspect}, define `resolve_type (type, obj, ctx) -> { ... }` inside `Schema.define`.")
596
- end
597
- @resolve_type_proc.call(ok_type, ok_object, ok_ctx)
598
- end
599
- end
600
-
601
- # This is a compatibility hack so that instance-level and class-level
602
- # methods can get correctness checks without calling one another
603
- # @api private
604
- def check_resolved_type(type, object, ctx = :__undefined__)
605
- if ctx == :__undefined__
606
- # Old method signature
607
- ctx = object
608
- object = type
609
- type = nil
610
- end
611
-
612
- if object.is_a?(GraphQL::Schema::Object)
613
- object = object.object
133
+ def deprecated_graphql_definition
134
+ graphql_definition(silence_deprecation_warning: true)
614
135
  end
615
136
 
616
- if type.respond_to?(:graphql_definition)
617
- type = type.graphql_definition
137
+ # @return [GraphQL::Subscriptions]
138
+ def subscriptions(inherited: true)
139
+ defined?(@subscriptions) ? @subscriptions : (inherited ? find_inherited_value(:subscriptions, nil) : nil)
618
140
  end
619
141
 
620
- # Prefer a type-local function; fall back to the schema-level function
621
- type_proc = type && type.resolve_type_proc
622
- type_result = if type_proc
623
- type_proc.call(object, ctx)
624
- else
625
- yield(type, object, ctx)
142
+ def subscriptions=(new_implementation)
143
+ @subscriptions = new_implementation
626
144
  end
627
145
 
628
- if type_result.nil?
629
- nil
630
- else
631
- after_lazy(type_result) do |resolved_type_result|
632
- if resolved_type_result.respond_to?(:graphql_definition)
633
- resolved_type_result = resolved_type_result.graphql_definition
634
- end
635
- if !resolved_type_result.is_a?(GraphQL::BaseType)
636
- type_str = "#{resolved_type_result} (#{resolved_type_result.class.name})"
637
- raise "resolve_type(#{object}) returned #{type_str}, but it should return a GraphQL type"
146
+ def trace_class(new_class = nil)
147
+ if new_class
148
+ @trace_class = new_class
149
+ elsif !defined?(@trace_class)
150
+ parent_trace_class = if superclass.respond_to?(:trace_class)
151
+ superclass.trace_class
638
152
  else
639
- resolved_type_result
153
+ GraphQL::Tracing::Trace
640
154
  end
155
+ @trace_class = Class.new(parent_trace_class)
641
156
  end
157
+ @trace_class
642
158
  end
643
- end
644
-
645
- def resolve_type=(new_resolve_type_proc)
646
- callable = GraphQL::BackwardsCompatibility.wrap_arity(new_resolve_type_proc, from: 2, to: 3, last: true, name: "Schema#resolve_type(type, obj, ctx)")
647
- @resolve_type_proc = callable
648
- end
649
-
650
- # Fetch an application object by its unique id
651
- # @param id [String] A unique identifier, provided previously by this GraphQL schema
652
- # @param ctx [GraphQL::Query::Context] The context for the current query
653
- # @return [Any] The application object identified by `id`
654
- def object_from_id(id, ctx)
655
- if @object_from_id_proc.nil?
656
- raise(GraphQL::RequiredImplementationMissingError, "Can't fetch an object for id \"#{id}\" because the schema's `object_from_id (id, ctx) -> { ... }` function is not defined")
657
- else
658
- @object_from_id_proc.call(id, ctx)
659
- end
660
- end
661
-
662
- # @param new_proc [#call] A new callable for fetching objects by ID
663
- def object_from_id=(new_proc)
664
- @object_from_id_proc = new_proc
665
- end
666
-
667
- # When we encounter a type error during query execution, we call this hook.
668
- #
669
- # You can use this hook to write a log entry,
670
- # add a {GraphQL::ExecutionError} to the response (with `ctx.add_error`)
671
- # or raise an exception and halt query execution.
672
- #
673
- # @example A `nil` is encountered by a non-null field
674
- # type_error ->(err, query_ctx) {
675
- # err.is_a?(GraphQL::InvalidNullError) # => true
676
- # }
677
- #
678
- # @example An object doesn't resolve to one of a {UnionType}'s members
679
- # type_error ->(err, query_ctx) {
680
- # err.is_a?(GraphQL::UnresolvedTypeError) # => true
681
- # }
682
- #
683
- # @see {DefaultTypeError} is the default behavior.
684
- # @param err [GraphQL::TypeError] The error encountered during execution
685
- # @param ctx [GraphQL::Query::Context] The context for the field where the error occurred
686
- # @return void
687
- def type_error(err, ctx)
688
- @type_error_proc.call(err, ctx)
689
- end
690
-
691
- # @param new_proc [#call] A new callable for handling type errors during execution
692
- def type_error=(new_proc)
693
- @type_error_proc = new_proc
694
- end
695
-
696
- # Can't delegate to `class`
697
- alias :_schema_class :class
698
- def_delegators :_schema_class, :unauthorized_object, :unauthorized_field, :inaccessible_fields
699
- def_delegators :_schema_class, :directive
700
- def_delegators :_schema_class, :error_handler
701
- def_delegators :_schema_class, :validate
702
-
703
-
704
- # Given this schema member, find the class-based definition object
705
- # whose `method_name` should be treated as an application hook
706
- # @see {.visible?}
707
- # @see {.accessible?}
708
- def call_on_type_class(member, method_name, context, default:)
709
- member = if member.respond_to?(:type_class)
710
- member.type_class
711
- else
712
- member
713
- end
714
-
715
- if member.respond_to?(:relay_node_type) && (t = member.relay_node_type)
716
- member = t
717
- end
718
-
719
- if member.respond_to?(method_name)
720
- member.public_send(method_name, context)
721
- else
722
- default
723
- end
724
- end
725
-
726
- def visible?(member, context)
727
- call_on_type_class(member, :visible?, context, default: true)
728
- end
729
-
730
- def accessible?(member, context)
731
- call_on_type_class(member, :accessible?, context, default: true)
732
- end
733
-
734
- # A function to call when {#execute} receives an invalid query string
735
- #
736
- # @see {DefaultParseError} is the default behavior.
737
- # @param err [GraphQL::ParseError] The error encountered during parsing
738
- # @param ctx [GraphQL::Query::Context] The context for the query where the error occurred
739
- # @return void
740
- def parse_error(err, ctx)
741
- @parse_error_proc.call(err, ctx)
742
- end
743
-
744
- # @param new_proc [#call] A new callable for handling parse errors during execution
745
- def parse_error=(new_proc)
746
- @parse_error_proc = new_proc
747
- end
748
-
749
- # Get a unique identifier from this object
750
- # @param object [Any] An application object
751
- # @param type [GraphQL::BaseType] The current type definition
752
- # @param ctx [GraphQL::Query::Context] the context for the current query
753
- # @return [String] a unique identifier for `object` which clients can use to refetch it
754
- def id_from_object(object, type, ctx)
755
- if @id_from_object_proc.nil?
756
- raise(GraphQL::RequiredImplementationMissingError, "Can't generate an ID for #{object.inspect} of type #{type}, schema's `id_from_object` must be defined")
757
- else
758
- @id_from_object_proc.call(object, type, ctx)
759
- end
760
- end
761
-
762
- # @param new_proc [#call] A new callable for generating unique IDs
763
- def id_from_object=(new_proc)
764
- @id_from_object_proc = new_proc
765
- end
766
-
767
- # Create schema with the result of an introspection query.
768
- # @param introspection_result [Hash] A response from {GraphQL::Introspection::INTROSPECTION_QUERY}
769
- # @return [GraphQL::Schema] the schema described by `input`
770
- def self.from_introspection(introspection_result)
771
- GraphQL::Schema::Loader.load(introspection_result)
772
- end
773
-
774
- # Create schema from an IDL schema or file containing an IDL definition.
775
- # @param definition_or_path [String] A schema definition string, or a path to a file containing the definition
776
- # @param default_resolve [<#call(type, field, obj, args, ctx)>] A callable for handling field resolution
777
- # @param parser [Object] An object for handling definition string parsing (must respond to `parse`)
778
- # @param using [Hash] Plugins to attach to the created schema with `use(key, value)`
779
- # @return [Class] the schema described by `document`
780
- def self.from_definition(definition_or_path, default_resolve: nil, parser: GraphQL.default_parser, using: {})
781
- # If the file ends in `.graphql`, treat it like a filepath
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
- )
789
- else
790
- GraphQL::Schema::BuildFromDefinition.from_definition(
791
- definition_or_path,
792
- default_resolve: default_resolve,
793
- parser: parser,
794
- using: using,
795
- )
796
- end
797
- end
798
-
799
- # Error that is raised when [#Schema#from_definition] is passed an invalid schema definition string.
800
- class InvalidDocumentError < Error; end;
801
-
802
- # Return the GraphQL IDL for the schema
803
- # @param context [Hash]
804
- # @param only [<#call(member, ctx)>]
805
- # @param except [<#call(member, ctx)>]
806
- # @return [String]
807
- def to_definition(only: nil, except: nil, context: {})
808
- GraphQL::Schema::Printer.print_schema(self, only: only, except: except, context: context)
809
- end
810
-
811
- # Return the GraphQL::Language::Document IDL AST for the schema
812
- # @param context [Hash]
813
- # @param only [<#call(member, ctx)>]
814
- # @param except [<#call(member, ctx)>]
815
- # @return [GraphQL::Language::Document]
816
- def to_document(only: nil, except: nil, context: {})
817
- GraphQL::Language::DocumentFromSchemaDefinition.new(self, only: only, except: except, context: context).document
818
- end
819
-
820
- # Return the Hash response of {Introspection::INTROSPECTION_QUERY}.
821
- # @param context [Hash]
822
- # @param only [<#call(member, ctx)>]
823
- # @param except [<#call(member, ctx)>]
824
- # @return [Hash] GraphQL result
825
- def as_json(only: nil, except: nil, context: {})
826
- execute(Introspection.query(include_deprecated_args: true), only: only, except: except, context: context).to_h
827
- end
828
-
829
- # Returns the JSON response of {Introspection::INTROSPECTION_QUERY}.
830
- # @see {#as_json}
831
- # @return [String]
832
- def to_json(*args)
833
- JSON.pretty_generate(as_json(*args))
834
- end
835
-
836
- def new_connections?
837
- !!connections
838
- end
839
-
840
- attr_accessor :connections
841
-
842
- class << self
843
- extend Forwardable
844
- # For compatibility, these methods all:
845
- # - Cause the Schema instance to be created, if it hasn't been created yet
846
- # - Delegate to that instance
847
- # Eventually, the methods will be moved into this class, removing the need for the singleton.
848
- def_delegators :deprecated_graphql_definition,
849
- # Execution
850
- :execution_strategy_for_operation,
851
- # Configuration
852
- :metadata, :redefine,
853
- :id_from_object_proc, :object_from_id_proc,
854
- :id_from_object=, :object_from_id=,
855
- :remove_handler
856
-
857
- def deprecated_graphql_definition
858
- graphql_definition(silence_deprecation_warning: true)
859
- end
860
-
861
- # @return [GraphQL::Subscriptions]
862
- attr_accessor :subscriptions
863
159
 
864
160
  # Returns the JSON response of {Introspection::INTROSPECTION_QUERY}.
865
161
  # @see {#as_json}
@@ -872,9 +168,22 @@ module GraphQL
872
168
  # @param context [Hash]
873
169
  # @param only [<#call(member, ctx)>]
874
170
  # @param except [<#call(member, ctx)>]
171
+ # @param include_deprecated_args [Boolean] If true, deprecated arguments will be included in the JSON response
172
+ # @param include_schema_description [Boolean] If true, the schema's description will be queried and included in the response
173
+ # @param include_is_repeatable [Boolean] If true, `isRepeatable: true|false` will be included with the schema's directives
174
+ # @param include_specified_by_url [Boolean] If true, scalar types' `specifiedByUrl:` will be included in the response
175
+ # @param include_is_one_of [Boolean] If true, `isOneOf: true|false` will be included with input objects
875
176
  # @return [Hash] GraphQL result
876
- def as_json(only: nil, except: nil, context: {})
877
- execute(Introspection.query(include_deprecated_args: true), only: only, except: except, context: context).to_h
177
+ def as_json(only: nil, except: nil, context: {}, include_deprecated_args: true, include_schema_description: false, include_is_repeatable: false, include_specified_by_url: false, include_is_one_of: false)
178
+ introspection_query = Introspection.query(
179
+ include_deprecated_args: include_deprecated_args,
180
+ include_schema_description: include_schema_description,
181
+ include_is_repeatable: include_is_repeatable,
182
+ include_is_one_of: include_is_one_of,
183
+ include_specified_by_url: include_specified_by_url,
184
+ )
185
+
186
+ execute(introspection_query, only: only, except: except, context: context).to_h
878
187
  end
879
188
 
880
189
  # Return the GraphQL IDL for the schema
@@ -911,17 +220,6 @@ module GraphQL
911
220
  @find_cache[path] ||= @finder.find(path)
912
221
  end
913
222
 
914
- def graphql_definition(silence_deprecation_warning: false)
915
- @graphql_definition ||= begin
916
- unless silence_deprecation_warning
917
- message = "Legacy `.graphql_definition` objects are deprecated and will be removed in GraphQL-Ruby 2.0. Use a class-based definition instead."
918
- caller_message = "\n\nCalled on #{self.inspect} from:\n #{caller(1, 25).map { |l| " #{l}" }.join("\n")}"
919
- GraphQL::Deprecation.warn(message + caller_message)
920
- end
921
- to_graphql(silence_deprecation_warning: silence_deprecation_warning)
922
- end
923
- end
924
-
925
223
  def default_filter
926
224
  GraphQL::Filter.new(except: default_mask)
927
225
  end
@@ -951,73 +249,6 @@ module GraphQL
951
249
  find_inherited_value(:plugins, EMPTY_ARRAY) + own_plugins
952
250
  end
953
251
 
954
- prepend Schema::Member::CachedGraphQLDefinition::DeprecatedToGraphQL
955
- def to_graphql
956
- schema_defn = self.new
957
- schema_defn.raise_definition_error = true
958
- schema_defn.query = query && query.graphql_definition(silence_deprecation_warning: true)
959
- schema_defn.mutation = mutation && mutation.graphql_definition(silence_deprecation_warning: true)
960
- schema_defn.subscription = subscription && subscription.graphql_definition(silence_deprecation_warning: true)
961
- schema_defn.validate_timeout = validate_timeout
962
- schema_defn.validate_max_errors = validate_max_errors
963
- schema_defn.max_complexity = max_complexity
964
- schema_defn.error_bubbling = error_bubbling
965
- schema_defn.max_depth = max_depth
966
- schema_defn.default_max_page_size = default_max_page_size
967
- schema_defn.orphan_types = orphan_types.map { |t| t.graphql_definition(silence_deprecation_warning: true) }
968
- schema_defn.disable_introspection_entry_points = disable_introspection_entry_points?
969
- schema_defn.disable_schema_introspection_entry_point = disable_schema_introspection_entry_point?
970
- schema_defn.disable_type_introspection_entry_point = disable_type_introspection_entry_point?
971
-
972
- prepped_dirs = {}
973
- directives.each { |k, v| prepped_dirs[k] = v.graphql_definition}
974
- schema_defn.directives = prepped_dirs
975
- schema_defn.introspection_namespace = introspection
976
- schema_defn.resolve_type = method(:resolve_type)
977
- schema_defn.object_from_id = method(:object_from_id)
978
- schema_defn.id_from_object = method(:id_from_object)
979
- schema_defn.type_error = method(:type_error)
980
- schema_defn.context_class = context_class
981
- schema_defn.cursor_encoder = cursor_encoder
982
- schema_defn.tracers.concat(tracers)
983
- schema_defn.query_analyzers.concat(query_analyzers)
984
- schema_defn.analysis_engine = analysis_engine
985
-
986
- schema_defn.middleware.concat(all_middleware)
987
- schema_defn.multiplex_analyzers.concat(multiplex_analyzers)
988
- schema_defn.query_execution_strategy = query_execution_strategy
989
- schema_defn.mutation_execution_strategy = mutation_execution_strategy
990
- schema_defn.subscription_execution_strategy = subscription_execution_strategy
991
- schema_defn.default_mask = default_mask
992
- instrumenters.each do |step, insts|
993
- insts.each do |inst|
994
- schema_defn.instrumenters[step] << inst
995
- end
996
- end
997
-
998
- lazy_methods.each do |lazy_class, value_method|
999
- schema_defn.lazy_methods.set(lazy_class, value_method)
1000
- end
1001
-
1002
- error_handler.each_rescue do |err_class, handler|
1003
- schema_defn.rescue_from(err_class, &handler)
1004
- end
1005
-
1006
- schema_defn.subscriptions ||= self.subscriptions
1007
-
1008
- if !schema_defn.interpreter?
1009
- schema_defn.instrumenters[:query] << GraphQL::Schema::Member::Instrumentation
1010
- end
1011
-
1012
- if new_connections?
1013
- schema_defn.connections = self.connections
1014
- end
1015
-
1016
- schema_defn.send(:rebuild_artifacts)
1017
-
1018
- schema_defn
1019
- end
1020
-
1021
252
  # Build a map of `{ name => type }` and return it
1022
253
  # @return [Hash<String => Class>] A dictionary of type classes by their GraphQL name
1023
254
  # @see get_type Which is more efficient for finding _one type_ by name, because it doesn't merge hashes.
@@ -1032,7 +263,9 @@ module GraphQL
1032
263
  if visible_t.nil?
1033
264
  visible_t = t
1034
265
  else
1035
- raise DuplicateNamesError, "Found two visible type definitions for `#{k}`: #{visible_t.inspect}, #{t.inspect}"
266
+ raise DuplicateNamesError.new(
267
+ duplicated_name: k, duplicated_definition_1: visible_t.inspect, duplicated_definition_2: t.inspect
268
+ )
1036
269
  end
1037
270
  end
1038
271
  end
@@ -1059,7 +292,9 @@ module GraphQL
1059
292
  if visible_t.nil?
1060
293
  visible_t = t
1061
294
  else
1062
- raise DuplicateNamesError, "Found two visible type definitions for `#{type_name}`: #{visible_t.inspect}, #{t.inspect}"
295
+ raise DuplicateNamesError.new(
296
+ duplicated_name: type_name, duplicated_definition_1: visible_t.inspect, duplicated_definition_2: t.inspect
297
+ )
1063
298
  end
1064
299
  end
1065
300
  end
@@ -1172,9 +407,7 @@ module GraphQL
1172
407
  stored_possible_types = own_possible_types[type.graphql_name]
1173
408
  visible_possible_types = if stored_possible_types && type.kind.interface?
1174
409
  stored_possible_types.select do |possible_type|
1175
- # Use `.graphql_name` comparison to match legacy vs class-based types.
1176
- # When we don't need to support legacy `.define` types, use `.include?(type)` instead.
1177
- possible_type.interfaces(context).any? { |interface| interface.graphql_name == type.graphql_name }
410
+ possible_type.interfaces(context).include?(type)
1178
411
  end
1179
412
  else
1180
413
  stored_possible_types
@@ -1309,6 +542,14 @@ module GraphQL
1309
542
  end
1310
543
  end
1311
544
 
545
+ def default_page_size(new_default_page_size = nil)
546
+ if new_default_page_size
547
+ @default_page_size = new_default_page_size
548
+ else
549
+ @default_page_size || find_inherited_value(:default_page_size)
550
+ end
551
+ end
552
+
1312
553
  def query_execution_strategy(new_query_execution_strategy = nil)
1313
554
  if new_query_execution_strategy
1314
555
  @query_execution_strategy = new_query_execution_strategy
@@ -1393,13 +634,11 @@ module GraphQL
1393
634
  end
1394
635
 
1395
636
  def using_ast_analysis?
1396
- analysis_engine == GraphQL::Analysis::AST
637
+ true
1397
638
  end
1398
639
 
1399
640
  def interpreter?
1400
- query_execution_strategy == GraphQL::Execution::Interpreter &&
1401
- mutation_execution_strategy == GraphQL::Execution::Interpreter &&
1402
- subscription_execution_strategy == GraphQL::Execution::Interpreter
641
+ true
1403
642
  end
1404
643
 
1405
644
  attr_writer :interpreter
@@ -1504,21 +743,62 @@ module GraphQL
1504
743
 
1505
744
  def rescue_from(*err_classes, &handler_block)
1506
745
  err_classes.each do |err_class|
1507
- error_handler.rescue_from(err_class, handler_block)
746
+ Execution::Errors.register_rescue_from(err_class, error_handlers[:subclass_handlers], handler_block)
747
+ end
748
+ end
749
+
750
+ NEW_HANDLER_HASH = ->(h, k) {
751
+ h[k] = {
752
+ class: k,
753
+ handler: nil,
754
+ subclass_handlers: Hash.new(&NEW_HANDLER_HASH),
755
+ }
756
+ }
757
+
758
+ def error_handlers
759
+ @error_handlers ||= {
760
+ class: nil,
761
+ handler: nil,
762
+ subclass_handlers: Hash.new(&NEW_HANDLER_HASH),
763
+ }
764
+ end
765
+
766
+ # @api private
767
+ def handle_or_reraise(context, err)
768
+ handler = Execution::Errors.find_handler_for(self, err.class)
769
+ if handler
770
+ obj = context[:current_object]
771
+ args = context[:current_arguments]
772
+ args = args && args.respond_to?(:keyword_arguments) ? args.keyword_arguments : nil
773
+ field = context[:current_field]
774
+ if obj.is_a?(GraphQL::Schema::Object)
775
+ obj = obj.object
776
+ end
777
+ handler[:handler].call(err, obj, args, context, field)
778
+ else
779
+ raise err
1508
780
  end
1509
781
  end
1510
782
 
1511
783
  # rubocop:disable Lint/DuplicateMethods
1512
784
  module ResolveTypeWithType
1513
785
  def resolve_type(type, obj, ctx)
1514
- first_resolved_type, resolved_value = if type.is_a?(Module) && type.respond_to?(:resolve_type)
786
+ maybe_lazy_resolve_type_result = if type.is_a?(Module) && type.respond_to?(:resolve_type)
1515
787
  type.resolve_type(obj, ctx)
1516
788
  else
1517
789
  super
1518
790
  end
1519
791
 
1520
- after_lazy(first_resolved_type) do |resolved_type|
1521
- if resolved_type.nil? || (resolved_type.is_a?(Module) && resolved_type.respond_to?(:kind)) || resolved_type.is_a?(GraphQL::BaseType)
792
+ after_lazy(maybe_lazy_resolve_type_result) do |resolve_type_result|
793
+ if resolve_type_result.is_a?(Array) && resolve_type_result.size == 2
794
+ resolved_type = resolve_type_result[0]
795
+ resolved_value = resolve_type_result[1]
796
+ else
797
+ resolved_type = resolve_type_result
798
+ resolved_value = obj
799
+ end
800
+
801
+ if resolved_type.nil? || (resolved_type.is_a?(Module) && resolved_type.respond_to?(:kind))
1522
802
  if resolved_value
1523
803
  [resolved_type, resolved_value]
1524
804
  else
@@ -1557,23 +837,16 @@ module GraphQL
1557
837
  end
1558
838
 
1559
839
  def visible?(member, ctx)
1560
- member.type_class.visible?(ctx)
840
+ member.visible?(ctx)
1561
841
  end
1562
842
 
1563
- def accessible?(member, ctx)
1564
- member.type_class.accessible?(ctx)
843
+ def schema_directive(dir_class, **options)
844
+ @own_schema_directives ||= []
845
+ Member::HasDirectives.add_directive(self, @own_schema_directives, dir_class, options)
1565
846
  end
1566
847
 
1567
- # This hook is called when a client tries to access one or more
1568
- # fields that fail the `accessible?` check.
1569
- #
1570
- # By default, an error is added to the response. Override this hook to
1571
- # track metrics or return a different error to the client.
1572
- #
1573
- # @param error [InaccessibleFieldsError] The analysis error for this check
1574
- # @return [AnalysisError, nil] Return an error to skip the query
1575
- def inaccessible_fields(error)
1576
- error
848
+ def schema_directives
849
+ Member::HasDirectives.get_directives(self, @own_schema_directives, :schema_directives)
1577
850
  end
1578
851
 
1579
852
  # This hook is called when an object fails an `authorized?` check.
@@ -1611,41 +884,33 @@ module GraphQL
1611
884
  unauthorized_object(unauthorized_error)
1612
885
  end
1613
886
 
1614
- def type_error(type_err, ctx)
1615
- DefaultTypeError.call(type_err, ctx)
887
+ def type_error(type_error, ctx)
888
+ case type_error
889
+ when GraphQL::InvalidNullError
890
+ ctx.errors << type_error
891
+ when GraphQL::UnresolvedTypeError, GraphQL::StringEncodingError, GraphQL::IntegerEncodingError
892
+ raise type_error
893
+ when GraphQL::IntegerDecodingError
894
+ nil
895
+ end
1616
896
  end
1617
897
 
1618
898
  # A function to call when {#execute} receives an invalid query string
1619
899
  #
1620
900
  # The default is to add the error to `context.errors`
1621
- # @param err [GraphQL::ParseError] The error encountered during parsing
901
+ # @param parse_err [GraphQL::ParseError] The error encountered during parsing
1622
902
  # @param ctx [GraphQL::Query::Context] The context for the query where the error occurred
1623
903
  # @return void
1624
904
  def parse_error(parse_err, ctx)
1625
905
  ctx.errors.push(parse_err)
1626
906
  end
1627
907
 
1628
- # @return [GraphQL::Execution::Errors]
1629
- def error_handler
1630
- @error_handler ||= GraphQL::Execution::Errors.new(self)
1631
- end
1632
-
1633
908
  def lazy_resolve(lazy_class, value_method)
1634
909
  lazy_methods.set(lazy_class, value_method)
1635
910
  end
1636
911
 
1637
912
  def instrument(instrument_step, instrumenter, options = {})
1638
- if instrument_step == :field
1639
- 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"
1640
- end
1641
-
1642
- step = if instrument_step == :field && options[:after_built_ins]
1643
- :field_after_built_ins
1644
- else
1645
- instrument_step
1646
- end
1647
-
1648
- own_instrumenters[step] << instrumenter
913
+ own_instrumenters[instrument_step] << instrumenter
1649
914
  end
1650
915
 
1651
916
  # Add several directives at once
@@ -1670,10 +935,17 @@ module GraphQL
1670
935
  "include" => GraphQL::Schema::Directive::Include,
1671
936
  "skip" => GraphQL::Schema::Directive::Skip,
1672
937
  "deprecated" => GraphQL::Schema::Directive::Deprecated,
938
+ "oneOf" => GraphQL::Schema::Directive::OneOf,
1673
939
  }.freeze
1674
940
  end
1675
941
 
1676
942
  def tracer(new_tracer)
943
+ if defined?(@trace_class) && !(@trace_class < GraphQL::Tracing::LegacyTrace)
944
+ raise ArgumentError, "Can't add tracer after configuring a `trace_class`, use GraphQL::Tracing::LegacyTrace to merge legacy tracers into a trace class instead."
945
+ elsif !defined?(@trace_class)
946
+ @trace_class = Class.new(GraphQL::Tracing::LegacyTrace)
947
+ end
948
+
1677
949
  own_tracers << new_tracer
1678
950
  end
1679
951
 
@@ -1681,10 +953,29 @@ module GraphQL
1681
953
  find_inherited_value(:tracers, EMPTY_ARRAY) + own_tracers
1682
954
  end
1683
955
 
1684
- def query_analyzer(new_analyzer)
1685
- if new_analyzer == GraphQL::Authorization::Analyzer
1686
- GraphQL::Deprecation.warn("The Authorization query analyzer is deprecated. Authorizing at query runtime is generally a better idea.")
956
+ # Mix `trace_mod` into this schema's `Trace` class so that its methods
957
+ # will be called at runtime.
958
+ #
959
+ # @param trace_mod [Module] A module that implements tracing methods
960
+ # @param options [Hash] Keywords that will be passed to the tracing class during `#initialize`
961
+ # @return [void]
962
+ def trace_with(trace_mod, **options)
963
+ trace_options.merge!(options)
964
+ trace_class.include(trace_mod)
965
+ end
966
+
967
+ def trace_options
968
+ @trace_options ||= superclass.respond_to?(:trace_options) ? superclass.trace_options.dup : {}
969
+ end
970
+
971
+ def new_trace(**options)
972
+ if defined?(@trace_options)
973
+ options = trace_options.merge(options)
1687
974
  end
975
+ trace_class.new(**options)
976
+ end
977
+
978
+ def query_analyzer(new_analyzer)
1688
979
  own_query_analyzers << new_analyzer
1689
980
  end
1690
981
 
@@ -1692,16 +983,6 @@ module GraphQL
1692
983
  find_inherited_value(:query_analyzers, EMPTY_ARRAY) + own_query_analyzers
1693
984
  end
1694
985
 
1695
- def middleware(new_middleware = nil)
1696
- if new_middleware
1697
- 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"
1698
- own_middleware << new_middleware
1699
- else
1700
- # TODO make sure this is cached when running a query
1701
- MiddlewareChain.new(steps: all_middleware, final_step: GraphQL::Execution::Execute::FieldResolveStep)
1702
- end
1703
- end
1704
-
1705
986
  def multiplex_analyzer(new_analyzer)
1706
987
  own_multiplex_analyzers << new_analyzer
1707
988
  end
@@ -1755,17 +1036,12 @@ module GraphQL
1755
1036
  # }
1756
1037
  #
1757
1038
  # @see {Query#initialize} for query keyword arguments
1758
- # @see {Execution::Multiplex#run_queries} for multiplex keyword arguments
1039
+ # @see {Execution::Multiplex#run_all} for multiplex keyword arguments
1759
1040
  # @param queries [Array<Hash>] Keyword arguments for each query
1760
1041
  # @param context [Hash] Multiplex-level context
1761
1042
  # @return [Array<Hash>] One result for each query in the input
1762
1043
  def multiplex(queries, **kwargs)
1763
- schema = if interpreter?
1764
- self
1765
- else
1766
- graphql_definition
1767
- end
1768
- GraphQL::Execution::Multiplex.run_all(schema, queries, **kwargs)
1044
+ GraphQL::Execution::Interpreter.run_all(self, queries, **kwargs)
1769
1045
  end
1770
1046
 
1771
1047
  def instrumenters
@@ -1777,12 +1053,10 @@ module GraphQL
1777
1053
 
1778
1054
  # @api private
1779
1055
  def add_subscription_extension_if_necessary
1780
- if interpreter? && !defined?(@subscription_extension_added) && subscription && self.subscriptions
1056
+ if !defined?(@subscription_extension_added) && subscription && self.subscriptions
1781
1057
  @subscription_extension_added = true
1782
- if subscription.singleton_class.ancestors.include?(Subscriptions::SubscriptionRoot)
1783
- GraphQL::Deprecation.warn("`extend Subscriptions::SubscriptionRoot` is no longer required; you may remove it from #{self}'s `subscription` root type (#{subscription}).")
1784
- else
1785
- subscription.all_field_definitions.each do |field|
1058
+ subscription.all_field_definitions.each do |field|
1059
+ if !field.extensions.any? { |ext| ext.is_a?(Subscriptions::DefaultSubscriptionResolveExtension) }
1786
1060
  field.extension(Subscriptions::DefaultSubscriptionResolveExtension)
1787
1061
  end
1788
1062
  end
@@ -1793,6 +1067,60 @@ module GraphQL
1793
1067
  query.context.errors.push(GraphQL::ExecutionError.new("This query is too large to execute."))
1794
1068
  end
1795
1069
 
1070
+ # Call the given block at the right time, either:
1071
+ # - Right away, if `value` is not registered with `lazy_resolve`
1072
+ # - After resolving `value`, if it's registered with `lazy_resolve` (eg, `Promise`)
1073
+ # @api private
1074
+ def after_lazy(value, &block)
1075
+ if lazy?(value)
1076
+ GraphQL::Execution::Lazy.new do
1077
+ result = sync_lazy(value)
1078
+ # The returned result might also be lazy, so check it, too
1079
+ after_lazy(result, &block)
1080
+ end
1081
+ else
1082
+ yield(value) if block_given?
1083
+ end
1084
+ end
1085
+
1086
+ # Override this method to handle lazy objects in a custom way.
1087
+ # @param value [Object] an instance of a class registered with {.lazy_resolve}
1088
+ # @return [Object] A GraphQL-ready (non-lazy) object
1089
+ # @api private
1090
+ def sync_lazy(value)
1091
+ lazy_method = lazy_method_name(value)
1092
+ if lazy_method
1093
+ synced_value = value.public_send(lazy_method)
1094
+ sync_lazy(synced_value)
1095
+ else
1096
+ value
1097
+ end
1098
+ end
1099
+
1100
+ # @return [Symbol, nil] The method name to lazily resolve `obj`, or nil if `obj`'s class wasn't registered with {#lazy_resolve}.
1101
+ def lazy_method_name(obj)
1102
+ lazy_methods.get(obj)
1103
+ end
1104
+
1105
+ # @return [Boolean] True if this object should be lazily resolved
1106
+ def lazy?(obj)
1107
+ !!lazy_method_name(obj)
1108
+ end
1109
+
1110
+ # Return a lazy if any of `maybe_lazies` are lazy,
1111
+ # otherwise, call the block eagerly and return the result.
1112
+ # @param maybe_lazies [Array]
1113
+ # @api private
1114
+ def after_any_lazies(maybe_lazies)
1115
+ if maybe_lazies.any? { |l| lazy?(l) }
1116
+ GraphQL::Execution::Lazy.all(maybe_lazies).then do |result|
1117
+ yield result
1118
+ end
1119
+ else
1120
+ yield maybe_lazies
1121
+ end
1122
+ end
1123
+
1796
1124
  private
1797
1125
 
1798
1126
  # @param t [Module, Array<Module>]
@@ -1902,68 +1230,12 @@ module GraphQL
1902
1230
  @defined_query_analyzers ||= []
1903
1231
  end
1904
1232
 
1905
- def all_middleware
1906
- find_inherited_value(:all_middleware, EMPTY_ARRAY) + own_middleware
1907
- end
1908
-
1909
- def own_middleware
1910
- @own_middleware ||= []
1911
- end
1912
-
1913
1233
  def own_multiplex_analyzers
1914
1234
  @own_multiplex_analyzers ||= []
1915
1235
  end
1916
1236
  end
1917
1237
 
1918
- def dataloader_class
1919
- self.class.dataloader_class
1920
- end
1921
-
1922
1238
  # Install these here so that subclasses will also install it.
1923
- use(GraphQL::Pagination::Connections)
1924
-
1925
- protected
1926
-
1927
- def rescues?
1928
- !!@rescue_middleware
1929
- end
1930
-
1931
- # Lazily create a middleware and add it to the schema
1932
- # (Don't add it if it's not used)
1933
- def rescue_middleware
1934
- @rescue_middleware ||= GraphQL::Schema::RescueMiddleware.new.tap { |m| middleware.insert(0, m) }
1935
- end
1936
-
1937
- private
1938
-
1939
- def rebuild_artifacts
1940
- if @rebuilding_artifacts
1941
- raise CyclicalDefinitionError, "Part of the schema build process re-triggered the schema build process, causing an infinite loop. Avoid using Schema#types, Schema#possible_types, and Schema#get_field during schema build."
1942
- else
1943
- @rebuilding_artifacts = true
1944
- @introspection_system = Schema::IntrospectionSystem.new(self)
1945
- traversal = Traversal.new(self)
1946
- @types = traversal.type_map
1947
- @root_types = [query, mutation, subscription]
1948
- @instrumented_field_map = traversal.instrumented_field_map
1949
- @type_reference_map = traversal.type_reference_map
1950
- @union_memberships = traversal.union_memberships
1951
- @find_cache = {}
1952
- @finder = Finder.new(self)
1953
- end
1954
- ensure
1955
- @rebuilding_artifacts = false
1956
- end
1957
-
1958
- class CyclicalDefinitionError < GraphQL::Error
1959
- end
1960
-
1961
- def with_definition_error_check
1962
- if @definition_error
1963
- raise @definition_error
1964
- else
1965
- yield
1966
- end
1967
- end
1239
+ self.connections = GraphQL::Pagination::Connections.new(schema: self)
1968
1240
  end
1969
1241
  end