graphql 2.0.13 → 2.3.10

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 (228) hide show
  1. checksums.yaml +4 -4
  2. data/lib/generators/graphql/install/mutation_root_generator.rb +2 -2
  3. data/lib/generators/graphql/install/templates/base_mutation.erb +2 -0
  4. data/lib/generators/graphql/install/templates/mutation_type.erb +2 -0
  5. data/lib/generators/graphql/install_generator.rb +3 -0
  6. data/lib/generators/graphql/mutation_delete_generator.rb +1 -1
  7. data/lib/generators/graphql/mutation_update_generator.rb +1 -1
  8. data/lib/generators/graphql/relay.rb +18 -1
  9. data/lib/generators/graphql/templates/base_argument.erb +2 -0
  10. data/lib/generators/graphql/templates/base_connection.erb +2 -0
  11. data/lib/generators/graphql/templates/base_edge.erb +2 -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_object.erb +2 -0
  17. data/lib/generators/graphql/templates/base_resolver.erb +6 -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/graphql_controller.erb +2 -0
  21. data/lib/generators/graphql/templates/loader.erb +2 -0
  22. data/lib/generators/graphql/templates/mutation.erb +2 -0
  23. data/lib/generators/graphql/templates/node_type.erb +2 -0
  24. data/lib/generators/graphql/templates/query_type.erb +2 -0
  25. data/lib/generators/graphql/templates/schema.erb +8 -0
  26. data/lib/graphql/analysis/analyzer.rb +89 -0
  27. data/lib/graphql/analysis/field_usage.rb +82 -0
  28. data/lib/graphql/analysis/max_query_complexity.rb +20 -0
  29. data/lib/graphql/analysis/max_query_depth.rb +20 -0
  30. data/lib/graphql/analysis/query_complexity.rb +183 -0
  31. data/lib/graphql/analysis/query_depth.rb +58 -0
  32. data/lib/graphql/analysis/visitor.rb +283 -0
  33. data/lib/graphql/analysis.rb +92 -1
  34. data/lib/graphql/backtrace/inspect_result.rb +0 -12
  35. data/lib/graphql/backtrace/table.rb +2 -2
  36. data/lib/graphql/backtrace/trace.rb +93 -0
  37. data/lib/graphql/backtrace/tracer.rb +1 -1
  38. data/lib/graphql/backtrace.rb +2 -1
  39. data/lib/graphql/coercion_error.rb +1 -9
  40. data/lib/graphql/dataloader/async_dataloader.rb +88 -0
  41. data/lib/graphql/dataloader/null_dataloader.rb +1 -1
  42. data/lib/graphql/dataloader/request.rb +5 -0
  43. data/lib/graphql/dataloader/source.rb +89 -45
  44. data/lib/graphql/dataloader.rb +115 -142
  45. data/lib/graphql/duration_encoding_error.rb +16 -0
  46. data/lib/graphql/execution/interpreter/argument_value.rb +5 -1
  47. data/lib/graphql/execution/interpreter/arguments.rb +1 -1
  48. data/lib/graphql/execution/interpreter/arguments_cache.rb +33 -33
  49. data/lib/graphql/execution/interpreter/resolve.rb +19 -0
  50. data/lib/graphql/execution/interpreter/runtime/graphql_result.rb +175 -0
  51. data/lib/graphql/execution/interpreter/runtime.rb +331 -455
  52. data/lib/graphql/execution/interpreter.rb +125 -61
  53. data/lib/graphql/execution/lazy.rb +6 -12
  54. data/lib/graphql/execution/lookahead.rb +124 -46
  55. data/lib/graphql/execution/multiplex.rb +3 -117
  56. data/lib/graphql/execution.rb +0 -1
  57. data/lib/graphql/introspection/directive_type.rb +3 -3
  58. data/lib/graphql/introspection/dynamic_fields.rb +1 -1
  59. data/lib/graphql/introspection/entry_points.rb +11 -5
  60. data/lib/graphql/introspection/field_type.rb +2 -2
  61. data/lib/graphql/introspection/schema_type.rb +10 -13
  62. data/lib/graphql/introspection/type_type.rb +17 -10
  63. data/lib/graphql/introspection.rb +3 -2
  64. data/lib/graphql/language/block_string.rb +34 -18
  65. data/lib/graphql/language/definition_slice.rb +1 -1
  66. data/lib/graphql/language/document_from_schema_definition.rb +75 -59
  67. data/lib/graphql/language/lexer.rb +358 -1506
  68. data/lib/graphql/language/nodes.rb +166 -93
  69. data/lib/graphql/language/parser.rb +795 -1953
  70. data/lib/graphql/language/printer.rb +340 -160
  71. data/lib/graphql/language/sanitized_printer.rb +21 -23
  72. data/lib/graphql/language/static_visitor.rb +167 -0
  73. data/lib/graphql/language/visitor.rb +188 -141
  74. data/lib/graphql/language.rb +61 -1
  75. data/lib/graphql/load_application_object_failed_error.rb +5 -1
  76. data/lib/graphql/pagination/active_record_relation_connection.rb +0 -8
  77. data/lib/graphql/pagination/array_connection.rb +6 -6
  78. data/lib/graphql/pagination/connection.rb +33 -6
  79. data/lib/graphql/pagination/mongoid_relation_connection.rb +1 -2
  80. data/lib/graphql/query/context/scoped_context.rb +101 -0
  81. data/lib/graphql/query/context.rb +117 -112
  82. data/lib/graphql/query/null_context.rb +12 -25
  83. data/lib/graphql/query/validation_pipeline.rb +6 -5
  84. data/lib/graphql/query/variables.rb +3 -3
  85. data/lib/graphql/query.rb +86 -30
  86. data/lib/graphql/railtie.rb +9 -6
  87. data/lib/graphql/rake_task.rb +29 -11
  88. data/lib/graphql/rubocop/graphql/base_cop.rb +1 -1
  89. data/lib/graphql/schema/addition.rb +59 -23
  90. data/lib/graphql/schema/always_visible.rb +11 -0
  91. data/lib/graphql/schema/argument.rb +55 -26
  92. data/lib/graphql/schema/base_64_encoder.rb +3 -5
  93. data/lib/graphql/schema/build_from_definition.rb +56 -32
  94. data/lib/graphql/schema/directive/one_of.rb +24 -0
  95. data/lib/graphql/schema/directive/specified_by.rb +14 -0
  96. data/lib/graphql/schema/directive/transform.rb +1 -1
  97. data/lib/graphql/schema/directive.rb +15 -3
  98. data/lib/graphql/schema/enum.rb +35 -24
  99. data/lib/graphql/schema/enum_value.rb +2 -3
  100. data/lib/graphql/schema/field/connection_extension.rb +2 -16
  101. data/lib/graphql/schema/field/scope_extension.rb +8 -1
  102. data/lib/graphql/schema/field.rb +147 -107
  103. data/lib/graphql/schema/field_extension.rb +1 -4
  104. data/lib/graphql/schema/find_inherited_value.rb +2 -7
  105. data/lib/graphql/schema/has_single_input_argument.rb +158 -0
  106. data/lib/graphql/schema/input_object.rb +47 -11
  107. data/lib/graphql/schema/interface.rb +15 -21
  108. data/lib/graphql/schema/introspection_system.rb +7 -17
  109. data/lib/graphql/schema/late_bound_type.rb +10 -0
  110. data/lib/graphql/schema/list.rb +2 -2
  111. data/lib/graphql/schema/loader.rb +2 -3
  112. data/lib/graphql/schema/member/base_dsl_methods.rb +18 -14
  113. data/lib/graphql/schema/member/build_type.rb +11 -3
  114. data/lib/graphql/schema/member/has_arguments.rb +170 -130
  115. data/lib/graphql/schema/member/has_ast_node.rb +12 -0
  116. data/lib/graphql/schema/member/has_deprecation_reason.rb +3 -4
  117. data/lib/graphql/schema/member/has_directives.rb +81 -61
  118. data/lib/graphql/schema/member/has_fields.rb +100 -38
  119. data/lib/graphql/schema/member/has_interfaces.rb +65 -10
  120. data/lib/graphql/schema/member/has_unresolved_type_error.rb +5 -1
  121. data/lib/graphql/schema/member/has_validators.rb +32 -6
  122. data/lib/graphql/schema/member/relay_shortcuts.rb +19 -0
  123. data/lib/graphql/schema/member/scoped.rb +19 -0
  124. data/lib/graphql/schema/member/type_system_helpers.rb +16 -0
  125. data/lib/graphql/schema/member/validates_input.rb +3 -3
  126. data/lib/graphql/schema/mutation.rb +7 -0
  127. data/lib/graphql/schema/object.rb +16 -5
  128. data/lib/graphql/schema/printer.rb +11 -8
  129. data/lib/graphql/schema/relay_classic_mutation.rb +7 -129
  130. data/lib/graphql/schema/resolver/has_payload_type.rb +9 -9
  131. data/lib/graphql/schema/resolver.rb +47 -32
  132. data/lib/graphql/schema/scalar.rb +3 -3
  133. data/lib/graphql/schema/subscription.rb +11 -4
  134. data/lib/graphql/schema/subset.rb +397 -0
  135. data/lib/graphql/schema/timeout.rb +25 -29
  136. data/lib/graphql/schema/type_expression.rb +2 -2
  137. data/lib/graphql/schema/type_membership.rb +3 -0
  138. data/lib/graphql/schema/union.rb +11 -2
  139. data/lib/graphql/schema/unique_within_type.rb +1 -1
  140. data/lib/graphql/schema/validator/all_validator.rb +60 -0
  141. data/lib/graphql/schema/validator.rb +4 -2
  142. data/lib/graphql/schema/warden.rb +238 -93
  143. data/lib/graphql/schema.rb +498 -103
  144. data/lib/graphql/static_validation/all_rules.rb +2 -1
  145. data/lib/graphql/static_validation/base_visitor.rb +7 -6
  146. data/lib/graphql/static_validation/definition_dependencies.rb +7 -1
  147. data/lib/graphql/static_validation/literal_validator.rb +24 -7
  148. data/lib/graphql/static_validation/rules/argument_literals_are_compatible.rb +1 -1
  149. data/lib/graphql/static_validation/rules/arguments_are_defined.rb +1 -1
  150. data/lib/graphql/static_validation/rules/directives_are_defined.rb +1 -2
  151. data/lib/graphql/static_validation/rules/fields_are_defined_on_type.rb +1 -1
  152. data/lib/graphql/static_validation/rules/fields_have_appropriate_selections.rb +12 -4
  153. data/lib/graphql/static_validation/rules/fields_will_merge.rb +10 -10
  154. data/lib/graphql/static_validation/rules/fragment_spreads_are_possible.rb +3 -3
  155. data/lib/graphql/static_validation/rules/fragment_types_exist.rb +1 -1
  156. data/lib/graphql/static_validation/rules/fragments_are_on_composite_types.rb +1 -1
  157. data/lib/graphql/static_validation/rules/mutation_root_exists.rb +1 -1
  158. data/lib/graphql/static_validation/rules/one_of_input_objects_are_valid.rb +66 -0
  159. data/lib/graphql/static_validation/rules/one_of_input_objects_are_valid_error.rb +29 -0
  160. data/lib/graphql/static_validation/rules/query_root_exists.rb +1 -1
  161. data/lib/graphql/static_validation/rules/required_arguments_are_present.rb +4 -4
  162. data/lib/graphql/static_validation/rules/required_input_object_attributes_are_present.rb +5 -5
  163. data/lib/graphql/static_validation/rules/subscription_root_exists.rb +1 -1
  164. data/lib/graphql/static_validation/rules/variable_default_values_are_correctly_typed.rb +18 -27
  165. data/lib/graphql/static_validation/rules/variable_usages_are_allowed.rb +1 -1
  166. data/lib/graphql/static_validation/rules/variables_are_input_types.rb +1 -1
  167. data/lib/graphql/static_validation/validation_context.rb +5 -5
  168. data/lib/graphql/static_validation/validator.rb +4 -1
  169. data/lib/graphql/static_validation.rb +0 -1
  170. data/lib/graphql/subscriptions/action_cable_subscriptions.rb +11 -4
  171. data/lib/graphql/subscriptions/broadcast_analyzer.rb +11 -5
  172. data/lib/graphql/subscriptions/event.rb +11 -10
  173. data/lib/graphql/subscriptions/serialize.rb +2 -0
  174. data/lib/graphql/subscriptions.rb +20 -13
  175. data/lib/graphql/testing/helpers.rb +151 -0
  176. data/lib/graphql/testing.rb +2 -0
  177. data/lib/graphql/tracing/active_support_notifications_trace.rb +16 -0
  178. data/lib/graphql/tracing/appoptics_trace.rb +251 -0
  179. data/lib/graphql/tracing/appoptics_tracing.rb +2 -2
  180. data/lib/graphql/tracing/appsignal_trace.rb +77 -0
  181. data/lib/graphql/tracing/data_dog_trace.rb +183 -0
  182. data/lib/graphql/tracing/data_dog_tracing.rb +9 -21
  183. data/lib/graphql/{execution/instrumentation.rb → tracing/legacy_hooks_trace.rb} +10 -28
  184. data/lib/graphql/tracing/legacy_trace.rb +69 -0
  185. data/lib/graphql/tracing/new_relic_trace.rb +75 -0
  186. data/lib/graphql/tracing/notifications_trace.rb +45 -0
  187. data/lib/graphql/tracing/platform_trace.rb +118 -0
  188. data/lib/graphql/tracing/platform_tracing.rb +17 -3
  189. data/lib/graphql/tracing/{prometheus_tracing → prometheus_trace}/graphql_collector.rb +4 -2
  190. data/lib/graphql/tracing/prometheus_trace.rb +89 -0
  191. data/lib/graphql/tracing/prometheus_tracing.rb +3 -3
  192. data/lib/graphql/tracing/scout_trace.rb +72 -0
  193. data/lib/graphql/tracing/sentry_trace.rb +112 -0
  194. data/lib/graphql/tracing/statsd_trace.rb +56 -0
  195. data/lib/graphql/tracing/trace.rb +76 -0
  196. data/lib/graphql/tracing.rb +20 -40
  197. data/lib/graphql/type_kinds.rb +7 -4
  198. data/lib/graphql/types/iso_8601_duration.rb +77 -0
  199. data/lib/graphql/types/relay/base_connection.rb +1 -1
  200. data/lib/graphql/types/relay/connection_behaviors.rb +68 -6
  201. data/lib/graphql/types/relay/edge_behaviors.rb +33 -5
  202. data/lib/graphql/types/relay/node_behaviors.rb +8 -2
  203. data/lib/graphql/types/relay/page_info_behaviors.rb +11 -2
  204. data/lib/graphql/types/relay.rb +0 -1
  205. data/lib/graphql/types/string.rb +1 -1
  206. data/lib/graphql/types.rb +1 -0
  207. data/lib/graphql/version.rb +1 -1
  208. data/lib/graphql.rb +27 -20
  209. data/readme.md +13 -3
  210. metadata +96 -47
  211. data/lib/graphql/analysis/ast/analyzer.rb +0 -84
  212. data/lib/graphql/analysis/ast/field_usage.rb +0 -57
  213. data/lib/graphql/analysis/ast/max_query_complexity.rb +0 -22
  214. data/lib/graphql/analysis/ast/max_query_depth.rb +0 -22
  215. data/lib/graphql/analysis/ast/query_complexity.rb +0 -230
  216. data/lib/graphql/analysis/ast/query_depth.rb +0 -55
  217. data/lib/graphql/analysis/ast/visitor.rb +0 -269
  218. data/lib/graphql/analysis/ast.rb +0 -81
  219. data/lib/graphql/deprecation.rb +0 -9
  220. data/lib/graphql/filter.rb +0 -53
  221. data/lib/graphql/language/lexer.rl +0 -280
  222. data/lib/graphql/language/parser.y +0 -554
  223. data/lib/graphql/language/token.rb +0 -34
  224. data/lib/graphql/schema/base_64_bp.rb +0 -26
  225. data/lib/graphql/schema/invalid_type_error.rb +0 -7
  226. data/lib/graphql/static_validation/type_stack.rb +0 -216
  227. data/lib/graphql/subscriptions/instrumentation.rb +0 -28
  228. data/lib/graphql/types/relay/default_relay.rb +0 -21
@@ -1,9 +1,10 @@
1
1
  # frozen_string_literal: true
2
+ require "logger"
2
3
  require "graphql/schema/addition"
4
+ require "graphql/schema/always_visible"
3
5
  require "graphql/schema/base_64_encoder"
4
6
  require "graphql/schema/find_inherited_value"
5
7
  require "graphql/schema/finder"
6
- require "graphql/schema/invalid_type_error"
7
8
  require "graphql/schema/introspection_system"
8
9
  require "graphql/schema/late_bound_type"
9
10
  require "graphql/schema/null_mask"
@@ -31,16 +32,20 @@ require "graphql/schema/union"
31
32
  require "graphql/schema/directive"
32
33
  require "graphql/schema/directive/deprecated"
33
34
  require "graphql/schema/directive/include"
35
+ require "graphql/schema/directive/one_of"
34
36
  require "graphql/schema/directive/skip"
35
37
  require "graphql/schema/directive/feature"
36
38
  require "graphql/schema/directive/flagged"
37
39
  require "graphql/schema/directive/transform"
40
+ require "graphql/schema/directive/specified_by"
38
41
  require "graphql/schema/type_membership"
39
42
 
40
43
  require "graphql/schema/resolver"
41
44
  require "graphql/schema/mutation"
45
+ require "graphql/schema/has_single_input_argument"
42
46
  require "graphql/schema/relay_classic_mutation"
43
47
  require "graphql/schema/subscription"
48
+ require "graphql/schema/subset"
44
49
 
45
50
  module GraphQL
46
51
  # A GraphQL schema which may be queried with {GraphQL::Query}.
@@ -58,10 +63,6 @@ module GraphQL
58
63
  # Schemas can restrict large incoming queries with `max_depth` and `max_complexity` configurations.
59
64
  # (These configurations can be overridden by specific calls to {Schema#execute})
60
65
  #
61
- # Schemas can specify how queries should be executed against them.
62
- # `query_execution_strategy`, `mutation_execution_strategy` and `subscription_execution_strategy`
63
- # each apply to corresponding root types.
64
- # #
65
66
  # @example defining a schema
66
67
  # class MySchema < GraphQL::Schema
67
68
  # query QueryType
@@ -109,9 +110,10 @@ module GraphQL
109
110
  # @param using [Hash] Plugins to attach to the created schema with `use(key, value)`
110
111
  # @return [Class] the schema described by `document`
111
112
  def from_definition(definition_or_path, default_resolve: nil, parser: GraphQL.default_parser, using: {})
112
- # If the file ends in `.graphql`, treat it like a filepath
113
- if definition_or_path.end_with?(".graphql")
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")
114
115
  GraphQL::Schema::BuildFromDefinition.from_definition_path(
116
+ self,
115
117
  definition_or_path,
116
118
  default_resolve: default_resolve,
117
119
  parser: parser,
@@ -119,6 +121,7 @@ module GraphQL
119
121
  )
120
122
  else
121
123
  GraphQL::Schema::BuildFromDefinition.from_definition(
124
+ self,
122
125
  definition_or_path,
123
126
  default_resolve: default_resolve,
124
127
  parser: parser,
@@ -140,6 +143,119 @@ module GraphQL
140
143
  @subscriptions = new_implementation
141
144
  end
142
145
 
146
+ # @param new_mode [Symbol] If configured, this will be used when `context: { trace_mode: ... }` isn't set.
147
+ def default_trace_mode(new_mode = nil)
148
+ if new_mode
149
+ @default_trace_mode = new_mode
150
+ elsif defined?(@default_trace_mode)
151
+ @default_trace_mode
152
+ elsif superclass.respond_to?(:default_trace_mode)
153
+ superclass.default_trace_mode
154
+ else
155
+ :default
156
+ end
157
+ end
158
+
159
+ def trace_class(new_class = nil)
160
+ if new_class
161
+ # If any modules were already added for `:default`,
162
+ # re-apply them here
163
+ mods = trace_modules_for(:default)
164
+ mods.each { |mod| new_class.include(mod) }
165
+ trace_mode(:default, new_class)
166
+ backtrace_class = Class.new(new_class)
167
+ backtrace_class.include(GraphQL::Backtrace::Trace)
168
+ trace_mode(:default_backtrace, backtrace_class)
169
+ end
170
+ trace_class_for(:default, build: true)
171
+ end
172
+
173
+ # @return [Class] Return the trace class to use for this mode, looking one up on the superclass if this Schema doesn't have one defined.
174
+ def trace_class_for(mode, build: false)
175
+ if (trace_class = own_trace_modes[mode])
176
+ trace_class
177
+ elsif superclass.respond_to?(:trace_class_for) && (trace_class = superclass.trace_class_for(mode, build: false))
178
+ trace_class
179
+ elsif build
180
+ own_trace_modes[mode] = build_trace_mode(mode)
181
+ else
182
+ nil
183
+ end
184
+ end
185
+
186
+ # Configure `trace_class` to be used whenever `context: { trace_mode: mode_name }` is requested.
187
+ # {default_trace_mode} is used when no `trace_mode: ...` is requested.
188
+ #
189
+ # When a `trace_class` is added this way, it will _not_ receive other modules added with `trace_with(...)`
190
+ # unless `trace_mode` is explicitly given. (This class will not receive any default trace modules.)
191
+ #
192
+ # Subclasses of the schema will use `trace_class` as a base class for this mode and those
193
+ # subclass also will _not_ receive default tracing modules.
194
+ #
195
+ # @param mode_name [Symbol]
196
+ # @param trace_class [Class] subclass of GraphQL::Tracing::Trace
197
+ # @return void
198
+ def trace_mode(mode_name, trace_class)
199
+ own_trace_modes[mode_name] = trace_class
200
+ nil
201
+ end
202
+
203
+ def own_trace_modes
204
+ @own_trace_modes ||= {}
205
+ end
206
+
207
+ module DefaultTraceClass
208
+ end
209
+
210
+ private_constant :DefaultTraceClass
211
+
212
+ def build_trace_mode(mode)
213
+ case mode
214
+ when :default
215
+ # Use the superclass's default mode if it has one, or else start an inheritance chain at the built-in base class.
216
+ base_class = (superclass.respond_to?(:trace_class_for) && superclass.trace_class_for(mode)) || GraphQL::Tracing::Trace
217
+ Class.new(base_class) do
218
+ include DefaultTraceClass
219
+ end
220
+ when :default_backtrace
221
+ schema_base_class = trace_class_for(:default, build: true)
222
+ Class.new(schema_base_class) do
223
+ include(GraphQL::Backtrace::Trace)
224
+ end
225
+ else
226
+ # First, see if the superclass has a custom-defined class for this.
227
+ # Then, if it doesn't, use this class's default trace
228
+ base_class = (superclass.respond_to?(:trace_class_for) && superclass.trace_class_for(mode)) || trace_class_for(:default, build: true)
229
+ # Prepare the default trace class if it hasn't been initialized yet
230
+ base_class ||= (own_trace_modes[:default] = build_trace_mode(:default))
231
+ mods = trace_modules_for(mode)
232
+ if base_class < DefaultTraceClass
233
+ mods = trace_modules_for(:default) + mods
234
+ end
235
+ # Copy the existing default options into this mode's options
236
+ default_options = trace_options_for(:default)
237
+ add_trace_options_for(mode, default_options)
238
+
239
+ Class.new(base_class) do
240
+ mods.any? && include(*mods)
241
+ end
242
+ end
243
+ end
244
+
245
+ def own_trace_modules
246
+ @own_trace_modules ||= Hash.new { |h, k| h[k] = [] }
247
+ end
248
+
249
+ # @return [Array<Module>] Modules added for tracing in `trace_mode`, including inherited ones
250
+ def trace_modules_for(trace_mode)
251
+ modules = own_trace_modules[trace_mode]
252
+ if superclass.respond_to?(:trace_modules_for)
253
+ modules += superclass.trace_modules_for(trace_mode)
254
+ end
255
+ modules
256
+ end
257
+
258
+
143
259
  # Returns the JSON response of {Introspection::INTROSPECTION_QUERY}.
144
260
  # @see {#as_json}
145
261
  # @return [String]
@@ -151,18 +267,29 @@ module GraphQL
151
267
  # @param context [Hash]
152
268
  # @param only [<#call(member, ctx)>]
153
269
  # @param except [<#call(member, ctx)>]
270
+ # @param include_deprecated_args [Boolean] If true, deprecated arguments will be included in the JSON response
271
+ # @param include_schema_description [Boolean] If true, the schema's description will be queried and included in the response
272
+ # @param include_is_repeatable [Boolean] If true, `isRepeatable: true|false` will be included with the schema's directives
273
+ # @param include_specified_by_url [Boolean] If true, scalar types' `specifiedByUrl:` will be included in the response
274
+ # @param include_is_one_of [Boolean] If true, `isOneOf: true|false` will be included with input objects
154
275
  # @return [Hash] GraphQL result
155
- def as_json(only: nil, except: nil, context: {})
156
- execute(Introspection.query(include_deprecated_args: true), only: only, except: except, context: context).to_h
276
+ def as_json(context: {}, include_deprecated_args: true, include_schema_description: false, include_is_repeatable: false, include_specified_by_url: false, include_is_one_of: false)
277
+ introspection_query = Introspection.query(
278
+ include_deprecated_args: include_deprecated_args,
279
+ include_schema_description: include_schema_description,
280
+ include_is_repeatable: include_is_repeatable,
281
+ include_is_one_of: include_is_one_of,
282
+ include_specified_by_url: include_specified_by_url,
283
+ )
284
+
285
+ execute(introspection_query, context: context).to_h
157
286
  end
158
287
 
159
288
  # Return the GraphQL IDL for the schema
160
289
  # @param context [Hash]
161
- # @param only [<#call(member, ctx)>]
162
- # @param except [<#call(member, ctx)>]
163
290
  # @return [String]
164
- def to_definition(only: nil, except: nil, context: {})
165
- GraphQL::Schema::Printer.print_schema(self, only: only, except: except, context: context)
291
+ def to_definition(context: {})
292
+ GraphQL::Schema::Printer.print_schema(self, context: context)
166
293
  end
167
294
 
168
295
  # Return the GraphQL::Language::Document IDL AST for the schema
@@ -190,18 +317,6 @@ module GraphQL
190
317
  @find_cache[path] ||= @finder.find(path)
191
318
  end
192
319
 
193
- def default_filter
194
- GraphQL::Filter.new(except: default_mask)
195
- end
196
-
197
- def default_mask(new_mask = nil)
198
- if new_mask
199
- @own_default_mask = new_mask
200
- else
201
- @own_default_mask || find_inherited_value(:default_mask, Schema::NullMask)
202
- end
203
- end
204
-
205
320
  def static_validator
206
321
  GraphQL::StaticValidation::Validator.new(schema: self)
207
322
  end
@@ -222,7 +337,7 @@ module GraphQL
222
337
  # Build a map of `{ name => type }` and return it
223
338
  # @return [Hash<String => Class>] A dictionary of type classes by their GraphQL name
224
339
  # @see get_type Which is more efficient for finding _one type_ by name, because it doesn't merge hashes.
225
- def types(context = GraphQL::Query::NullContext)
340
+ def types(context = GraphQL::Query::NullContext.instance)
226
341
  all_types = non_introspection_types.merge(introspection_system.types)
227
342
  visible_types = {}
228
343
  all_types.each do |k, v|
@@ -249,26 +364,30 @@ module GraphQL
249
364
 
250
365
  # @param type_name [String]
251
366
  # @return [Module, nil] A type, or nil if there's no type called `type_name`
252
- def get_type(type_name, context = GraphQL::Query::NullContext)
367
+ def get_type(type_name, context = GraphQL::Query::NullContext.instance)
253
368
  local_entry = own_types[type_name]
254
369
  type_defn = case local_entry
255
370
  when nil
256
371
  nil
257
372
  when Array
258
- visible_t = nil
259
- warden = Warden.from_context(context)
260
- local_entry.each do |t|
261
- if warden.visible_type?(t, context)
262
- if visible_t.nil?
263
- visible_t = t
264
- else
265
- raise DuplicateNamesError.new(
266
- duplicated_name: type_name, duplicated_definition_1: visible_t.inspect, duplicated_definition_2: t.inspect
267
- )
373
+ if context.respond_to?(:types) && context.types.is_a?(GraphQL::Schema::Subset)
374
+ local_entry
375
+ else
376
+ visible_t = nil
377
+ warden = Warden.from_context(context)
378
+ local_entry.each do |t|
379
+ if warden.visible_type?(t, context)
380
+ if visible_t.nil?
381
+ visible_t = t
382
+ else
383
+ raise DuplicateNamesError.new(
384
+ duplicated_name: type_name, duplicated_definition_1: visible_t.inspect, duplicated_definition_2: t.inspect
385
+ )
386
+ end
268
387
  end
269
388
  end
389
+ visible_t
270
390
  end
271
- visible_t
272
391
  when Module
273
392
  local_entry
274
393
  else
@@ -280,6 +399,11 @@ module GraphQL
280
399
  (superclass.respond_to?(:get_type) ? superclass.get_type(type_name, context) : nil)
281
400
  end
282
401
 
402
+ # @return [Boolean] Does this schema have _any_ definition for a type named `type_name`, regardless of visibility?
403
+ def has_defined_type?(type_name)
404
+ own_types.key?(type_name) || introspection_system.types.key?(type_name) || (superclass.respond_to?(:has_defined_type?) ? superclass.has_defined_type?(type_name) : false)
405
+ end
406
+
283
407
  # @api private
284
408
  attr_writer :connections
285
409
 
@@ -365,16 +489,50 @@ module GraphQL
365
489
  @root_types
366
490
  end
367
491
 
492
+ def warden_class
493
+ if defined?(@warden_class)
494
+ @warden_class
495
+ elsif superclass.respond_to?(:warden_class)
496
+ superclass.warden_class
497
+ else
498
+ GraphQL::Schema::Warden
499
+ end
500
+ end
501
+
502
+ attr_writer :warden_class
503
+
504
+ def subset_class
505
+ if defined?(@subset_class)
506
+ @subset_class
507
+ elsif superclass.respond_to?(:subset_class)
508
+ superclass.subset_class
509
+ else
510
+ GraphQL::Schema::Subset
511
+ end
512
+ end
513
+
514
+ attr_writer :subset_class, :use_schema_subset
515
+
516
+ def use_schema_subset?
517
+ if defined?(@use_schema_subset)
518
+ @use_schema_subset
519
+ elsif superclass.respond_to?(:use_schema_subset?)
520
+ superclass.use_schema_subset?
521
+ else
522
+ false
523
+ end
524
+ end
525
+
368
526
  # @param type [Module] The type definition whose possible types you want to see
369
527
  # @return [Hash<String, Module>] All possible types, if no `type` is given.
370
528
  # @return [Array<Module>] Possible types for `type`, if it's given.
371
- def possible_types(type = nil, context = GraphQL::Query::NullContext)
529
+ def possible_types(type = nil, context = GraphQL::Query::NullContext.instance)
372
530
  if type
373
531
  # TODO duck-typing `.possible_types` would probably be nicer here
374
532
  if type.kind.union?
375
533
  type.possible_types(context: context)
376
534
  else
377
- stored_possible_types = own_possible_types[type.graphql_name]
535
+ stored_possible_types = own_possible_types[type]
378
536
  visible_possible_types = if stored_possible_types && type.kind.interface?
379
537
  stored_possible_types.select do |possible_type|
380
538
  possible_type.interfaces(context).include?(type)
@@ -383,7 +541,7 @@ module GraphQL
383
541
  stored_possible_types
384
542
  end
385
543
  visible_possible_types ||
386
- introspection_system.possible_types[type.graphql_name] ||
544
+ introspection_system.possible_types[type] ||
387
545
  (
388
546
  superclass.respond_to?(:possible_types) ?
389
547
  superclass.possible_types(type, context) :
@@ -421,18 +579,12 @@ module GraphQL
421
579
  attr_writer :dataloader_class
422
580
 
423
581
  def references_to(to_type = nil, from: nil)
424
- @own_references_to ||= Hash.new { |h, k| h[k] = [] }
425
582
  if to_type
426
- if !to_type.is_a?(String)
427
- to_type = to_type.graphql_name
428
- end
429
-
430
583
  if from
431
- @own_references_to[to_type] << from
584
+ refs = own_references_to[to_type] ||= []
585
+ refs << from
432
586
  else
433
- own_refs = @own_references_to[to_type]
434
- inherited_refs = find_inherited_value(:references_to, EMPTY_HASH)[to_type] || EMPTY_ARRAY
435
- own_refs + inherited_refs
587
+ get_references_to(to_type) || EMPTY_ARRAY
436
588
  end
437
589
  else
438
590
  # `@own_references_to` can be quite large for big schemas,
@@ -440,19 +592,18 @@ module GraphQL
440
592
  # So optimize the most common case -- don't create a duplicate Hash.
441
593
  inherited_value = find_inherited_value(:references_to, EMPTY_HASH)
442
594
  if inherited_value.any?
443
- inherited_value.merge(@own_references_to)
595
+ inherited_value.merge(own_references_to)
444
596
  else
445
- @own_references_to
597
+ own_references_to
446
598
  end
447
599
  end
448
600
  end
449
601
 
450
- def type_from_ast(ast_node, context: nil)
451
- type_owner = context ? context.warden : self
452
- GraphQL::Schema::TypeExpression.build_type(type_owner, ast_node)
602
+ def type_from_ast(ast_node, context: self.query_class.new(self, "{ __typename }").context)
603
+ GraphQL::Schema::TypeExpression.build_type(context.query.types, ast_node)
453
604
  end
454
605
 
455
- def get_field(type_or_name, field_name, context = GraphQL::Query::NullContext)
606
+ def get_field(type_or_name, field_name, context = GraphQL::Query::NullContext.instance)
456
607
  parent_type = case type_or_name
457
608
  when LateBoundType
458
609
  get_type(type_or_name.name, context)
@@ -475,7 +626,7 @@ module GraphQL
475
626
  end
476
627
  end
477
628
 
478
- def get_fields(type, context = GraphQL::Query::NullContext)
629
+ def get_fields(type, context = GraphQL::Query::NullContext.instance)
479
630
  type.fields(context)
480
631
  end
481
632
 
@@ -512,6 +663,17 @@ module GraphQL
512
663
  end
513
664
  end
514
665
 
666
+ # A limit on the number of tokens to accept on incoming query strings.
667
+ # Use this to prevent parsing maliciously-large query strings.
668
+ # @return [nil, Integer]
669
+ def max_query_string_tokens(new_max_tokens = NOT_CONFIGURED)
670
+ if NOT_CONFIGURED.equal?(new_max_tokens)
671
+ defined?(@max_query_string_tokens) ? @max_query_string_tokens : find_inherited_value(:max_query_string_tokens)
672
+ else
673
+ @max_query_string_tokens = new_max_tokens
674
+ end
675
+ end
676
+
515
677
  def default_page_size(new_default_page_size = nil)
516
678
  if new_default_page_size
517
679
  @default_page_size = new_default_page_size
@@ -520,27 +682,39 @@ module GraphQL
520
682
  end
521
683
  end
522
684
 
523
- def query_execution_strategy(new_query_execution_strategy = nil)
685
+ def query_execution_strategy(new_query_execution_strategy = nil, deprecation_warning: true)
686
+ if deprecation_warning
687
+ warn "GraphQL::Schema.query_execution_strategy is deprecated without replacement. Use `GraphQL::Query.new` directly to create and execute a custom query instead."
688
+ warn " #{caller(1, 1).first}"
689
+ end
524
690
  if new_query_execution_strategy
525
691
  @query_execution_strategy = new_query_execution_strategy
526
692
  else
527
- @query_execution_strategy || find_inherited_value(:query_execution_strategy, self.default_execution_strategy)
693
+ @query_execution_strategy || (superclass.respond_to?(:query_execution_strategy) ? superclass.query_execution_strategy(deprecation_warning: false) : self.default_execution_strategy)
528
694
  end
529
695
  end
530
696
 
531
- def mutation_execution_strategy(new_mutation_execution_strategy = nil)
697
+ def mutation_execution_strategy(new_mutation_execution_strategy = nil, deprecation_warning: true)
698
+ if deprecation_warning
699
+ warn "GraphQL::Schema.mutation_execution_strategy is deprecated without replacement. Use `GraphQL::Query.new` directly to create and execute a custom query instead."
700
+ warn " #{caller(1, 1).first}"
701
+ end
532
702
  if new_mutation_execution_strategy
533
703
  @mutation_execution_strategy = new_mutation_execution_strategy
534
704
  else
535
- @mutation_execution_strategy || find_inherited_value(:mutation_execution_strategy, self.default_execution_strategy)
705
+ @mutation_execution_strategy || (superclass.respond_to?(:mutation_execution_strategy) ? superclass.mutation_execution_strategy(deprecation_warning: false) : self.default_execution_strategy)
536
706
  end
537
707
  end
538
708
 
539
- def subscription_execution_strategy(new_subscription_execution_strategy = nil)
709
+ def subscription_execution_strategy(new_subscription_execution_strategy = nil, deprecation_warning: true)
710
+ if deprecation_warning
711
+ warn "GraphQL::Schema.subscription_execution_strategy is deprecated without replacement. Use `GraphQL::Query.new` directly to create and execute a custom query instead."
712
+ warn " #{caller(1, 1).first}"
713
+ end
540
714
  if new_subscription_execution_strategy
541
715
  @subscription_execution_strategy = new_subscription_execution_strategy
542
716
  else
543
- @subscription_execution_strategy || find_inherited_value(:subscription_execution_strategy, self.default_execution_strategy)
717
+ @subscription_execution_strategy || (superclass.respond_to?(:subscription_execution_strategy) ? superclass.subscription_execution_strategy(deprecation_warning: false) : self.default_execution_strategy)
544
718
  end
545
719
  end
546
720
 
@@ -565,7 +739,7 @@ module GraphQL
565
739
  else
566
740
  string_or_document
567
741
  end
568
- query = GraphQL::Query.new(self, document: doc, context: context)
742
+ query = query_class.new(self, document: doc, context: context)
569
743
  validator_opts = { schema: self }
570
744
  rules && (validator_opts[:rules] = rules)
571
745
  validator = GraphQL::StaticValidation::Validator.new(**validator_opts)
@@ -573,6 +747,14 @@ module GraphQL
573
747
  res[:errors]
574
748
  end
575
749
 
750
+ def query_class(new_query_class = NOT_CONFIGURED)
751
+ if NOT_CONFIGURED.equal?(new_query_class)
752
+ @query_class || (superclass.respond_to?(:query_class) ? superclass.query_class : GraphQL::Query)
753
+ else
754
+ @query_class = new_query_class
755
+ end
756
+ end
757
+
576
758
  attr_writer :validate_max_errors
577
759
 
578
760
  def validate_max_errors(new_validate_max_errors = nil)
@@ -587,9 +769,10 @@ module GraphQL
587
769
 
588
770
  attr_writer :max_complexity
589
771
 
590
- def max_complexity(max_complexity = nil)
772
+ def max_complexity(max_complexity = nil, count_introspection_fields: true)
591
773
  if max_complexity
592
774
  @max_complexity = max_complexity
775
+ @max_complexity_count_introspection_fields = count_introspection_fields
593
776
  elsif defined?(@max_complexity)
594
777
  @max_complexity
595
778
  else
@@ -597,6 +780,14 @@ module GraphQL
597
780
  end
598
781
  end
599
782
 
783
+ def max_complexity_count_introspection_fields
784
+ if defined?(@max_complexity_count_introspection_fields)
785
+ @max_complexity_count_introspection_fields
786
+ else
787
+ find_inherited_value(:max_complexity_count_introspection_fields, true)
788
+ end
789
+ end
790
+
600
791
  attr_writer :analysis_engine
601
792
 
602
793
  def analysis_engine
@@ -615,6 +806,7 @@ module GraphQL
615
806
 
616
807
  def error_bubbling(new_error_bubbling = nil)
617
808
  if !new_error_bubbling.nil?
809
+ warn("error_bubbling(#{new_error_bubbling.inspect}) is deprecated; the default value of `false` will be the only option in GraphQL-Ruby 3.0")
618
810
  @error_bubbling = new_error_bubbling
619
811
  else
620
812
  @error_bubbling.nil? ? find_inherited_value(:error_bubbling) : @error_bubbling
@@ -625,9 +817,10 @@ module GraphQL
625
817
 
626
818
  attr_writer :max_depth
627
819
 
628
- def max_depth(new_max_depth = nil)
820
+ def max_depth(new_max_depth = nil, count_introspection_fields: true)
629
821
  if new_max_depth
630
822
  @max_depth = new_max_depth
823
+ @count_introspection_fields = count_introspection_fields
631
824
  elsif defined?(@max_depth)
632
825
  @max_depth
633
826
  else
@@ -635,6 +828,14 @@ module GraphQL
635
828
  end
636
829
  end
637
830
 
831
+ def count_introspection_fields
832
+ if defined?(@count_introspection_fields)
833
+ @count_introspection_fields
834
+ else
835
+ find_inherited_value(:count_introspection_fields, true)
836
+ end
837
+ end
838
+
638
839
  def disable_introspection_entry_points
639
840
  @disable_introspection_entry_points = true
640
841
  # TODO: this clears the cache made in `def types`. But this is not a great solution.
@@ -677,14 +878,54 @@ module GraphQL
677
878
  end
678
879
  end
679
880
 
881
+ # @param new_extra_types [Module] Type definitions to include in printing and introspection, even though they aren't referenced in the schema
882
+ # @return [Array<Module>] Type definitions added to this schema
883
+ def extra_types(*new_extra_types)
884
+ if new_extra_types.any?
885
+ new_extra_types = new_extra_types.flatten
886
+ @own_extra_types ||= []
887
+ @own_extra_types.concat(new_extra_types)
888
+ end
889
+ inherited_et = find_inherited_value(:extra_types, nil)
890
+ if inherited_et
891
+ if @own_extra_types
892
+ inherited_et + @own_extra_types
893
+ else
894
+ inherited_et
895
+ end
896
+ else
897
+ @own_extra_types || EMPTY_ARRAY
898
+ end
899
+ end
900
+
680
901
  def orphan_types(*new_orphan_types)
681
902
  if new_orphan_types.any?
682
903
  new_orphan_types = new_orphan_types.flatten
904
+ non_object_types = new_orphan_types.reject { |ot| ot.is_a?(Class) && ot < GraphQL::Schema::Object }
905
+ if non_object_types.any?
906
+ raise ArgumentError, <<~ERR
907
+ Only object type classes should be added as `orphan_types(...)`.
908
+
909
+ - Remove these no-op types from `orphan_types`: #{non_object_types.map { |t| "#{t.inspect} (#{t.kind.name})"}.join(", ")}
910
+ - See https://graphql-ruby.org/type_definitions/interfaces.html#orphan-types
911
+
912
+ To add other types to your schema, you might want `extra_types`: https://graphql-ruby.org/schema/definition.html#extra-types
913
+ ERR
914
+ end
683
915
  add_type_and_traverse(new_orphan_types, root: false)
684
916
  own_orphan_types.concat(new_orphan_types.flatten)
685
917
  end
686
918
 
687
- find_inherited_value(:orphan_types, EMPTY_ARRAY) + own_orphan_types
919
+ inherited_ot = find_inherited_value(:orphan_types, nil)
920
+ if inherited_ot
921
+ if own_orphan_types.any?
922
+ inherited_ot + own_orphan_types
923
+ else
924
+ inherited_ot
925
+ end
926
+ else
927
+ own_orphan_types
928
+ end
688
929
  end
689
930
 
690
931
  def default_execution_strategy
@@ -703,6 +944,26 @@ module GraphQL
703
944
  end
704
945
  end
705
946
 
947
+ def default_logger(new_default_logger = NOT_CONFIGURED)
948
+ if NOT_CONFIGURED.equal?(new_default_logger)
949
+ if defined?(@default_logger)
950
+ @default_logger
951
+ elsif superclass.respond_to?(:default_logger)
952
+ superclass.default_logger
953
+ elsif defined?(Rails) && Rails.respond_to?(:logger) && (rails_logger = Rails.logger)
954
+ rails_logger
955
+ else
956
+ def_logger = Logger.new($stdout)
957
+ def_logger.info! # It doesn't output debug info by default
958
+ def_logger
959
+ end
960
+ elsif new_default_logger == nil
961
+ @default_logger = Logger.new(IO::NULL)
962
+ else
963
+ @default_logger = new_default_logger
964
+ end
965
+ end
966
+
706
967
  def context_class(new_context_class = nil)
707
968
  if new_context_class
708
969
  @context_class = new_context_class
@@ -737,11 +998,10 @@ module GraphQL
737
998
  def handle_or_reraise(context, err)
738
999
  handler = Execution::Errors.find_handler_for(self, err.class)
739
1000
  if handler
740
- runtime_info = context.namespace(:interpreter) || {}
741
- obj = runtime_info[:current_object]
742
- args = runtime_info[:current_arguments]
743
- args = args && args.keyword_arguments
744
- field = runtime_info[:current_field]
1001
+ obj = context[:current_object]
1002
+ args = context[:current_arguments]
1003
+ args = args && args.respond_to?(:keyword_arguments) ? args.keyword_arguments : nil
1004
+ field = context[:current_field]
745
1005
  if obj.is_a?(GraphQL::Schema::Object)
746
1006
  obj = obj.object
747
1007
  end
@@ -770,11 +1030,7 @@ module GraphQL
770
1030
  end
771
1031
 
772
1032
  if resolved_type.nil? || (resolved_type.is_a?(Module) && resolved_type.respond_to?(:kind))
773
- if resolved_value
774
- [resolved_type, resolved_value]
775
- else
776
- resolved_type
777
- end
1033
+ [resolved_type, resolved_value]
778
1034
  else
779
1035
  raise ".resolve_type should return a type definition, but got #{resolved_type.inspect} (#{resolved_type.class}) from `resolve_type(#{type}, #{obj}, #{ctx})`"
780
1036
  end
@@ -783,17 +1039,19 @@ module GraphQL
783
1039
  end
784
1040
 
785
1041
  def resolve_type(type, obj, ctx)
786
- if type.kind.object?
787
- type
788
- else
789
- raise GraphQL::RequiredImplementationMissingError, "#{self.name}.resolve_type(type, obj, ctx) must be implemented to use Union types or Interface types (tried to resolve: #{type.name})"
790
- end
1042
+ raise GraphQL::RequiredImplementationMissingError, "#{self.name}.resolve_type(type, obj, ctx) must be implemented to use Union types, Interface types, or `loads:` (tried to resolve: #{type.name})"
791
1043
  end
792
1044
  # rubocop:enable Lint/DuplicateMethods
793
1045
 
794
1046
  def inherited(child_class)
795
1047
  if self == GraphQL::Schema
796
1048
  child_class.directives(default_directives.values)
1049
+ child_class.extend(SubclassGetReferencesTo)
1050
+ end
1051
+ # Make sure the child class has these built out, so that
1052
+ # subclasses can be modified by later calls to `trace_with`
1053
+ own_trace_modes.each do |name, _class|
1054
+ child_class.own_trace_modes[name] = child_class.build_trace_mode(name)
797
1055
  end
798
1056
  child_class.singleton_class.prepend(ResolveTypeWithType)
799
1057
  super
@@ -811,22 +1069,19 @@ module GraphQL
811
1069
  member.visible?(ctx)
812
1070
  end
813
1071
 
814
- def accessible?(member, ctx)
815
- member.accessible?(ctx)
1072
+ def schema_directive(dir_class, **options)
1073
+ @own_schema_directives ||= []
1074
+ Member::HasDirectives.add_directive(self, @own_schema_directives, dir_class, options)
816
1075
  end
817
1076
 
818
- # This hook is called when a client tries to access one or more
819
- # fields that fail the `accessible?` check.
820
- #
821
- # By default, an error is added to the response. Override this hook to
822
- # track metrics or return a different error to the client.
823
- #
824
- # @param error [InaccessibleFieldsError] The analysis error for this check
825
- # @return [AnalysisError, nil] Return an error to skip the query
826
- def inaccessible_fields(error)
827
- error
1077
+ def schema_directives
1078
+ Member::HasDirectives.get_directives(self, @own_schema_directives, :schema_directives)
828
1079
  end
829
1080
 
1081
+ # Called when a type is needed by name at runtime
1082
+ def load_type(type_name, ctx)
1083
+ get_type(type_name, ctx)
1084
+ end
830
1085
  # This hook is called when an object fails an `authorized?` check.
831
1086
  # You might report to your bug tracker here, so you can correct
832
1087
  # the field resolvers not to return unauthorized objects.
@@ -876,7 +1131,7 @@ module GraphQL
876
1131
  # A function to call when {#execute} receives an invalid query string
877
1132
  #
878
1133
  # The default is to add the error to `context.errors`
879
- # @param err [GraphQL::ParseError] The error encountered during parsing
1134
+ # @param parse_err [GraphQL::ParseError] The error encountered during parsing
880
1135
  # @param ctx [GraphQL::Query::Context] The context for the query where the error occurred
881
1136
  # @return void
882
1137
  def parse_error(parse_err, ctx)
@@ -888,6 +1143,12 @@ module GraphQL
888
1143
  end
889
1144
 
890
1145
  def instrument(instrument_step, instrumenter, options = {})
1146
+ warn <<~WARN
1147
+ Schema.instrument is deprecated, use `trace_with` instead: https://graphql-ruby.org/queries/tracing.html"
1148
+ (From `#{self}.instrument(#{instrument_step}, #{instrumenter})` at #{caller(1, 1).first})
1149
+
1150
+ WARN
1151
+ trace_with(Tracing::LegacyHooksTrace)
891
1152
  own_instrumenters[instrument_step] << instrumenter
892
1153
  end
893
1154
 
@@ -898,7 +1159,12 @@ module GraphQL
898
1159
  new_directives.flatten.each { |d| directive(d) }
899
1160
  end
900
1161
 
901
- find_inherited_value(:directives, default_directives).merge(own_directives)
1162
+ inherited_dirs = find_inherited_value(:directives, default_directives)
1163
+ if own_directives.any?
1164
+ inherited_dirs.merge(own_directives)
1165
+ else
1166
+ inherited_dirs
1167
+ end
902
1168
  end
903
1169
 
904
1170
  # Attach a single directive to this schema
@@ -913,10 +1179,21 @@ module GraphQL
913
1179
  "include" => GraphQL::Schema::Directive::Include,
914
1180
  "skip" => GraphQL::Schema::Directive::Skip,
915
1181
  "deprecated" => GraphQL::Schema::Directive::Deprecated,
1182
+ "oneOf" => GraphQL::Schema::Directive::OneOf,
1183
+ "specifiedBy" => GraphQL::Schema::Directive::SpecifiedBy,
916
1184
  }.freeze
917
1185
  end
918
1186
 
919
- def tracer(new_tracer)
1187
+ def tracer(new_tracer, silence_deprecation_warning: false)
1188
+ if !silence_deprecation_warning
1189
+ warn("`Schema.tracer(#{new_tracer.inspect})` is deprecated; use module-based `trace_with` instead. See: https://graphql-ruby.org/queries/tracing.html")
1190
+ warn " #{caller(1, 1).first}"
1191
+ end
1192
+ default_trace = trace_class_for(:default, build: true)
1193
+ if default_trace.nil? || !(default_trace < GraphQL::Tracing::CallLegacyTracers)
1194
+ trace_with(GraphQL::Tracing::CallLegacyTracers)
1195
+ end
1196
+
920
1197
  own_tracers << new_tracer
921
1198
  end
922
1199
 
@@ -924,6 +1201,90 @@ module GraphQL
924
1201
  find_inherited_value(:tracers, EMPTY_ARRAY) + own_tracers
925
1202
  end
926
1203
 
1204
+ # Mix `trace_mod` into this schema's `Trace` class so that its methods
1205
+ # will be called at runtime.
1206
+ #
1207
+ # @param trace_mod [Module] A module that implements tracing methods
1208
+ # @param mode [Symbol] Trace module will only be used for this trade mode
1209
+ # @param options [Hash] Keywords that will be passed to the tracing class during `#initialize`
1210
+ # @return [void]
1211
+ def trace_with(trace_mod, mode: :default, **options)
1212
+ if mode.is_a?(Array)
1213
+ mode.each { |m| trace_with(trace_mod, mode: m, **options) }
1214
+ else
1215
+ tc = own_trace_modes[mode] ||= build_trace_mode(mode)
1216
+ tc.include(trace_mod)
1217
+ own_trace_modules[mode] << trace_mod
1218
+ add_trace_options_for(mode, options)
1219
+ if mode == :default
1220
+ # This module is being added as a default tracer. If any other mode classes
1221
+ # have already been created, but get their default behavior from a superclass,
1222
+ # Then mix this into this schema's subclass.
1223
+ # (But don't mix it into mode classes that aren't default-based.)
1224
+ own_trace_modes.each do |other_mode_name, other_mode_class|
1225
+ if other_mode_class < DefaultTraceClass
1226
+ # Don't add it back to the inheritance tree if it's already there
1227
+ if !(other_mode_class < trace_mod)
1228
+ other_mode_class.include(trace_mod)
1229
+ end
1230
+ # Add any options so they'll be available
1231
+ add_trace_options_for(other_mode_name, options)
1232
+ end
1233
+ end
1234
+ end
1235
+ end
1236
+ nil
1237
+ end
1238
+
1239
+ # The options hash for this trace mode
1240
+ # @return [Hash]
1241
+ def trace_options_for(mode)
1242
+ @trace_options_for_mode ||= {}
1243
+ @trace_options_for_mode[mode] ||= begin
1244
+ # It may be time to create an options hash for a mode that wasn't registered yet.
1245
+ # Mix in the default options in that case.
1246
+ default_options = mode == :default ? EMPTY_HASH : trace_options_for(:default)
1247
+ # Make sure this returns a new object so that other hashes aren't modified later
1248
+ if superclass.respond_to?(:trace_options_for)
1249
+ superclass.trace_options_for(mode).merge(default_options)
1250
+ else
1251
+ default_options.dup
1252
+ end
1253
+ end
1254
+ end
1255
+
1256
+ # Create a trace instance which will include the trace modules specified for the optional mode.
1257
+ #
1258
+ # If no `mode:` is given, then {default_trace_mode} will be used.
1259
+ #
1260
+ # @param mode [Symbol] Trace modules for this trade mode will be included
1261
+ # @param options [Hash] Keywords that will be passed to the tracing class during `#initialize`
1262
+ # @return [Tracing::Trace]
1263
+ def new_trace(mode: nil, **options)
1264
+ target = options[:query] || options[:multiplex]
1265
+ mode ||= target && target.context[:trace_mode]
1266
+
1267
+ trace_mode = if mode
1268
+ mode
1269
+ elsif target && target.context[:backtrace]
1270
+ if default_trace_mode != :default
1271
+ raise ArgumentError, "Can't use `context[:backtrace]` with a custom default trace mode (`#{dm.inspect}`)"
1272
+ else
1273
+ own_trace_modes[:default_backtrace] ||= build_trace_mode(:default_backtrace)
1274
+ options_trace_mode = :default
1275
+ :default_backtrace
1276
+ end
1277
+ else
1278
+ default_trace_mode
1279
+ end
1280
+
1281
+ options_trace_mode ||= trace_mode
1282
+ base_trace_options = trace_options_for(options_trace_mode)
1283
+ trace_options = base_trace_options.merge(options)
1284
+ trace_class_for_mode = trace_class_for(trace_mode, build: true)
1285
+ trace_class_for_mode.new(**trace_options)
1286
+ end
1287
+
927
1288
  def query_analyzer(new_analyzer)
928
1289
  own_query_analyzers << new_analyzer
929
1290
  end
@@ -950,7 +1311,7 @@ module GraphQL
950
1311
 
951
1312
  # Execute a query on itself.
952
1313
  # @see {Query#initialize} for arguments.
953
- # @return [Hash] query result, ready to be serialized as JSON
1314
+ # @return [GraphQL::Query::Result] query result, ready to be serialized as JSON
954
1315
  def execute(query_str = nil, **kwargs)
955
1316
  if query_str
956
1317
  kwargs[:query] = query_str
@@ -960,7 +1321,9 @@ module GraphQL
960
1321
  {
961
1322
  backtrace: ctx[:backtrace],
962
1323
  tracers: ctx[:tracers],
1324
+ trace: ctx[:trace],
963
1325
  dataloader: ctx[:dataloader],
1326
+ trace_mode: ctx[:trace_mode],
964
1327
  }
965
1328
  else
966
1329
  {}
@@ -988,9 +1351,9 @@ module GraphQL
988
1351
  # @see {Execution::Multiplex#run_all} for multiplex keyword arguments
989
1352
  # @param queries [Array<Hash>] Keyword arguments for each query
990
1353
  # @param context [Hash] Multiplex-level context
991
- # @return [Array<Hash>] One result for each query in the input
1354
+ # @return [Array<GraphQL::Query::Result>] One result for each query in the input
992
1355
  def multiplex(queries, **kwargs)
993
- GraphQL::Execution::Multiplex.run_all(self, queries, **kwargs)
1356
+ GraphQL::Execution::Interpreter.run_all(self, queries, **kwargs)
994
1357
  end
995
1358
 
996
1359
  def instrumenters
@@ -1072,6 +1435,12 @@ module GraphQL
1072
1435
 
1073
1436
  private
1074
1437
 
1438
+ def add_trace_options_for(mode, new_options)
1439
+ t_opts = trace_options_for(mode)
1440
+ t_opts.merge!(new_options)
1441
+ nil
1442
+ end
1443
+
1075
1444
  # @param t [Module, Array<Module>]
1076
1445
  # @return [void]
1077
1446
  def add_type_and_traverse(t, root:)
@@ -1115,7 +1484,8 @@ module GraphQL
1115
1484
  own_union_memberships.merge!(addition.union_memberships)
1116
1485
 
1117
1486
  addition.references.each { |thing, pointers|
1118
- pointers.each { |pointer| references_to(thing, from: pointer) }
1487
+ prev_refs = own_references_to[thing] || []
1488
+ own_references_to[thing] = prev_refs | pointers.to_a
1119
1489
  }
1120
1490
 
1121
1491
  addition.directives.each { |dir_class| own_directives[dir_class.graphql_name] = dir_class }
@@ -1133,7 +1503,7 @@ module GraphQL
1133
1503
  else
1134
1504
  @lazy_methods = GraphQL::Execution::Lazy::LazyMethodMap.new
1135
1505
  @lazy_methods.set(GraphQL::Execution::Lazy, :value)
1136
- @lazy_methods.set(GraphQL::Dataloader::Request, :load)
1506
+ @lazy_methods.set(GraphQL::Dataloader::Request, :load_with_deprecation_warning)
1137
1507
  end
1138
1508
  end
1139
1509
  @lazy_methods
@@ -1143,6 +1513,10 @@ module GraphQL
1143
1513
  @own_types ||= {}
1144
1514
  end
1145
1515
 
1516
+ def own_references_to
1517
+ @own_references_to ||= {}.tap(&:compare_by_identity)
1518
+ end
1519
+
1146
1520
  def non_introspection_types
1147
1521
  find_inherited_value(:non_introspection_types, EMPTY_HASH).merge(own_types)
1148
1522
  end
@@ -1156,7 +1530,7 @@ module GraphQL
1156
1530
  end
1157
1531
 
1158
1532
  def own_possible_types
1159
- @own_possible_types ||= {}
1533
+ @own_possible_types ||= {}.tap(&:compare_by_identity)
1160
1534
  end
1161
1535
 
1162
1536
  def own_union_memberships
@@ -1182,6 +1556,27 @@ module GraphQL
1182
1556
  def own_multiplex_analyzers
1183
1557
  @own_multiplex_analyzers ||= []
1184
1558
  end
1559
+
1560
+ # This is overridden in subclasses to check the inheritance chain
1561
+ def get_references_to(type_defn)
1562
+ own_references_to[type_defn]
1563
+ end
1564
+ end
1565
+
1566
+ module SubclassGetReferencesTo
1567
+ def get_references_to(type_defn)
1568
+ own_refs = own_references_to[type_defn]
1569
+ inherited_refs = superclass.references_to(type_defn)
1570
+ if inherited_refs&.any?
1571
+ if own_refs&.any?
1572
+ own_refs + inherited_refs
1573
+ else
1574
+ inherited_refs
1575
+ end
1576
+ else
1577
+ own_refs
1578
+ end
1579
+ end
1185
1580
  end
1186
1581
 
1187
1582
  # Install these here so that subclasses will also install it.