graphql 2.0.21 → 2.0.32

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (65) hide show
  1. checksums.yaml +4 -4
  2. data/lib/generators/graphql/mutation_delete_generator.rb +1 -1
  3. data/lib/generators/graphql/mutation_update_generator.rb +1 -1
  4. data/lib/generators/graphql/relay.rb +18 -1
  5. data/lib/graphql/backtrace.rb +0 -4
  6. data/lib/graphql/dataloader/source.rb +69 -45
  7. data/lib/graphql/dataloader.rb +4 -4
  8. data/lib/graphql/execution/interpreter/arguments_cache.rb +31 -30
  9. data/lib/graphql/execution/interpreter/runtime.rb +122 -101
  10. data/lib/graphql/execution/interpreter.rb +1 -2
  11. data/lib/graphql/execution/lookahead.rb +1 -1
  12. data/lib/graphql/filter.rb +2 -1
  13. data/lib/graphql/introspection/entry_points.rb +1 -1
  14. data/lib/graphql/language/document_from_schema_definition.rb +16 -9
  15. data/lib/graphql/language/lexer.rb +89 -57
  16. data/lib/graphql/language/nodes.rb +3 -0
  17. data/lib/graphql/language/parser.rb +706 -691
  18. data/lib/graphql/language/parser.y +1 -0
  19. data/lib/graphql/language/printer.rb +28 -14
  20. data/lib/graphql/language/visitor.rb +64 -61
  21. data/lib/graphql/query/context.rb +16 -7
  22. data/lib/graphql/query/null_context.rb +8 -18
  23. data/lib/graphql/query/validation_pipeline.rb +2 -1
  24. data/lib/graphql/query.rb +37 -12
  25. data/lib/graphql/schema/addition.rb +38 -12
  26. data/lib/graphql/schema/always_visible.rb +10 -0
  27. data/lib/graphql/schema/argument.rb +8 -10
  28. data/lib/graphql/schema/build_from_definition.rb +8 -7
  29. data/lib/graphql/schema/directive.rb +1 -1
  30. data/lib/graphql/schema/enum_value.rb +2 -2
  31. data/lib/graphql/schema/field/connection_extension.rb +1 -1
  32. data/lib/graphql/schema/field.rb +26 -15
  33. data/lib/graphql/schema/input_object.rb +9 -7
  34. data/lib/graphql/schema/interface.rb +5 -1
  35. data/lib/graphql/schema/introspection_system.rb +1 -1
  36. data/lib/graphql/schema/member/build_type.rb +10 -2
  37. data/lib/graphql/schema/member/has_arguments.rb +9 -7
  38. data/lib/graphql/schema/member/has_directives.rb +1 -1
  39. data/lib/graphql/schema/member/has_fields.rb +1 -1
  40. data/lib/graphql/schema/member/has_interfaces.rb +1 -1
  41. data/lib/graphql/schema/member/type_system_helpers.rb +1 -1
  42. data/lib/graphql/schema/object.rb +6 -1
  43. data/lib/graphql/schema/printer.rb +3 -1
  44. data/lib/graphql/schema/relay_classic_mutation.rb +1 -1
  45. data/lib/graphql/schema/resolver.rb +12 -10
  46. data/lib/graphql/schema/timeout.rb +1 -1
  47. data/lib/graphql/schema/validator.rb +1 -1
  48. data/lib/graphql/schema/warden.rb +37 -4
  49. data/lib/graphql/schema.rb +92 -23
  50. data/lib/graphql/tracing/appoptics_trace.rb +35 -11
  51. data/lib/graphql/tracing/appsignal_trace.rb +4 -0
  52. data/lib/graphql/tracing/data_dog_trace.rb +89 -50
  53. data/lib/graphql/tracing/data_dog_tracing.rb +7 -21
  54. data/lib/graphql/tracing/legacy_trace.rb +5 -1
  55. data/lib/graphql/tracing/notifications_trace.rb +7 -0
  56. data/lib/graphql/tracing/platform_trace.rb +26 -12
  57. data/lib/graphql/tracing/prometheus_trace.rb +4 -0
  58. data/lib/graphql/tracing/scout_trace.rb +3 -0
  59. data/lib/graphql/tracing/statsd_trace.rb +4 -0
  60. data/lib/graphql/tracing.rb +1 -0
  61. data/lib/graphql/types/relay/connection_behaviors.rb +1 -1
  62. data/lib/graphql/types/relay/edge_behaviors.rb +1 -1
  63. data/lib/graphql/version.rb +1 -1
  64. data/readme.md +1 -1
  65. metadata +36 -24
@@ -150,6 +150,7 @@ rule
150
150
  | REPEATABLE
151
151
  | TRUE
152
152
  | FALSE
153
+ | NULL
153
154
  | operation_type
154
155
  | schema_keyword
155
156
 
@@ -131,7 +131,7 @@ module GraphQL
131
131
  "$#{variable_identifier.name}".dup
132
132
  end
133
133
 
134
- def print_schema_definition(schema)
134
+ def print_schema_definition(schema, extension: false)
135
135
  has_conventional_names = (schema.query.nil? || schema.query == 'Query') &&
136
136
  (schema.mutation.nil? || schema.mutation == 'Mutation') &&
137
137
  (schema.subscription.nil? || schema.subscription == 'Subscription')
@@ -140,7 +140,7 @@ module GraphQL
140
140
  return
141
141
  end
142
142
 
143
- out = "schema".dup
143
+ out = extension ? "extend schema".dup : "schema".dup
144
144
  if schema.directives.any?
145
145
  schema.directives.each do |dir|
146
146
  out << "\n "
@@ -164,14 +164,14 @@ module GraphQL
164
164
  out
165
165
  end
166
166
 
167
- def print_scalar_type_definition(scalar_type)
168
- out = print_description(scalar_type)
167
+ def print_scalar_type_definition(scalar_type, extension: false)
168
+ out = extension ? "extend ".dup : print_description(scalar_type)
169
169
  out << "scalar #{scalar_type.name}"
170
170
  out << print_directives(scalar_type.directives)
171
171
  end
172
172
 
173
- def print_object_type_definition(object_type)
174
- out = print_description(object_type)
173
+ def print_object_type_definition(object_type, extension: false)
174
+ out = extension ? "extend ".dup : print_description(object_type)
175
175
  out << "type #{object_type.name}"
176
176
  out << print_implements(object_type) unless object_type.interfaces.empty?
177
177
  out << print_directives(object_type.directives)
@@ -210,23 +210,23 @@ module GraphQL
210
210
  out << print_directives(field.directives)
211
211
  end
212
212
 
213
- def print_interface_type_definition(interface_type)
214
- out = print_description(interface_type)
213
+ def print_interface_type_definition(interface_type, extension: false)
214
+ out = extension ? "extend ".dup : print_description(interface_type)
215
215
  out << "interface #{interface_type.name}"
216
216
  out << print_implements(interface_type) if interface_type.interfaces.any?
217
217
  out << print_directives(interface_type.directives)
218
218
  out << print_field_definitions(interface_type.fields)
219
219
  end
220
220
 
221
- def print_union_type_definition(union_type)
222
- out = print_description(union_type)
221
+ def print_union_type_definition(union_type, extension: false)
222
+ out = extension ? "extend ".dup : print_description(union_type)
223
223
  out << "union #{union_type.name}"
224
224
  out << print_directives(union_type.directives)
225
225
  out << " = " + union_type.types.map(&:name).join(" | ")
226
226
  end
227
227
 
228
- def print_enum_type_definition(enum_type)
229
- out = print_description(enum_type)
228
+ def print_enum_type_definition(enum_type, extension: false)
229
+ out = extension ? "extend ".dup : print_description(enum_type)
230
230
  out << "enum #{enum_type.name}#{print_directives(enum_type.directives)} {\n"
231
231
  enum_type.values.each.with_index do |value, i|
232
232
  out << print_description(value, indent: ' ', first_in_block: i == 0)
@@ -241,8 +241,8 @@ module GraphQL
241
241
  out << "\n"
242
242
  end
243
243
 
244
- def print_input_object_type_definition(input_object_type)
245
- out = print_description(input_object_type)
244
+ def print_input_object_type_definition(input_object_type, extension: false)
245
+ out = extension ? "extend ".dup : print_description(input_object_type)
246
246
  out << "input #{input_object_type.name}"
247
247
  out << print_directives(input_object_type.directives)
248
248
  if !input_object_type.fields.empty?
@@ -347,24 +347,38 @@ module GraphQL
347
347
  print_variable_identifier(node)
348
348
  when Nodes::SchemaDefinition
349
349
  print_schema_definition(node)
350
+ when Nodes::SchemaExtension
351
+ print_schema_definition(node, extension: true)
350
352
  when Nodes::ScalarTypeDefinition
351
353
  print_scalar_type_definition(node)
354
+ when Nodes::ScalarTypeExtension
355
+ print_scalar_type_definition(node, extension: true)
352
356
  when Nodes::ObjectTypeDefinition
353
357
  print_object_type_definition(node)
358
+ when Nodes::ObjectTypeExtension
359
+ print_object_type_definition(node, extension: true)
354
360
  when Nodes::InputValueDefinition
355
361
  print_input_value_definition(node)
356
362
  when Nodes::FieldDefinition
357
363
  print_field_definition(node)
358
364
  when Nodes::InterfaceTypeDefinition
359
365
  print_interface_type_definition(node)
366
+ when Nodes::InterfaceTypeExtension
367
+ print_interface_type_definition(node, extension: true)
360
368
  when Nodes::UnionTypeDefinition
361
369
  print_union_type_definition(node)
370
+ when Nodes::UnionTypeExtension
371
+ print_union_type_definition(node, extension: true)
362
372
  when Nodes::EnumTypeDefinition
363
373
  print_enum_type_definition(node)
374
+ when Nodes::EnumTypeExtension
375
+ print_enum_type_definition(node, extension: true)
364
376
  when Nodes::EnumValueDefinition
365
377
  print_enum_value_definition(node)
366
378
  when Nodes::InputObjectTypeDefinition
367
379
  print_input_object_type_definition(node)
380
+ when Nodes::InputObjectTypeExtension
381
+ print_input_object_type_definition(node, extension: true)
368
382
  when Nodes::DirectiveDefinition
369
383
  print_directive_definition(node)
370
384
  when FalseClass, Float, Integer, NilClass, String, TrueClass, Symbol
@@ -76,67 +76,6 @@ module GraphQL
76
76
  end
77
77
  end
78
78
 
79
- # We don't use `alias` here because it breaks `super`
80
- def self.make_visit_methods(ast_node_class)
81
- node_method = ast_node_class.visit_method
82
- children_of_type = ast_node_class.children_of_type
83
- child_visit_method = :"#{node_method}_children"
84
-
85
- class_eval(<<-RUBY, __FILE__, __LINE__ + 1)
86
- # The default implementation for visiting an AST node.
87
- # It doesn't _do_ anything, but it continues to visiting the node's children.
88
- # To customize this hook, override one of its make_visit_methods (or the base method?)
89
- # in your subclasses.
90
- #
91
- # For compatibility, it calls hook procs, too.
92
- # @param node [GraphQL::Language::Nodes::AbstractNode] the node being visited
93
- # @param parent [GraphQL::Language::Nodes::AbstractNode, nil] the previously-visited node, or `nil` if this is the root node.
94
- # @return [Array, nil] If there were modifications, it returns an array of new nodes, otherwise, it returns `nil`.
95
- def #{node_method}(node, parent)
96
- if node.equal?(DELETE_NODE)
97
- # This might be passed to `super(DELETE_NODE, ...)`
98
- # by a user hook, don't want to keep visiting in that case.
99
- [node, parent]
100
- else
101
- # Run hooks if there are any
102
- new_node = node
103
- no_hooks = !@visitors.key?(node.class)
104
- if no_hooks || begin_visit(new_node, parent)
105
- #{
106
- if method_defined?(child_visit_method)
107
- "new_node = #{child_visit_method}(new_node)"
108
- elsif children_of_type
109
- children_of_type.map do |child_accessor, child_class|
110
- "node.#{child_accessor}.each do |child_node|
111
- new_child_and_node = #{child_class.visit_method}_with_modifications(child_node, new_node)
112
- # Reassign `node` in case the child hook makes a modification
113
- if new_child_and_node.is_a?(Array)
114
- new_node = new_child_and_node[1]
115
- end
116
- end"
117
- end.join("\n")
118
- else
119
- ""
120
- end
121
- }
122
- end
123
- end_visit(new_node, parent) unless no_hooks
124
-
125
- if new_node.equal?(node)
126
- [node, parent]
127
- else
128
- [new_node, parent]
129
- end
130
- end
131
- end
132
-
133
- def #{node_method}_with_modifications(node, parent)
134
- new_node_and_new_parent = #{node_method}(node, parent)
135
- apply_modifications(node, parent, new_node_and_new_parent)
136
- end
137
- RUBY
138
- end
139
-
140
79
  def on_document_children(document_node)
141
80
  new_node = document_node
142
81
  document_node.children.each do |child_node|
@@ -237,6 +176,68 @@ module GraphQL
237
176
  new_node
238
177
  end
239
178
 
179
+ # rubocop:disable Development/NoEvalCop This eval takes static inputs at load-time
180
+
181
+ def self.make_visit_methods(ast_node_class)
182
+ node_method = ast_node_class.visit_method
183
+ children_of_type = ast_node_class.children_of_type
184
+ child_visit_method = :"#{node_method}_children"
185
+
186
+ class_eval(<<-RUBY, __FILE__, __LINE__ + 1)
187
+ # The default implementation for visiting an AST node.
188
+ # It doesn't _do_ anything, but it continues to visiting the node's children.
189
+ # To customize this hook, override one of its make_visit_methods (or the base method?)
190
+ # in your subclasses.
191
+ #
192
+ # For compatibility, it calls hook procs, too.
193
+ # @param node [GraphQL::Language::Nodes::AbstractNode] the node being visited
194
+ # @param parent [GraphQL::Language::Nodes::AbstractNode, nil] the previously-visited node, or `nil` if this is the root node.
195
+ # @return [Array, nil] If there were modifications, it returns an array of new nodes, otherwise, it returns `nil`.
196
+ def #{node_method}(node, parent)
197
+ if node.equal?(DELETE_NODE)
198
+ # This might be passed to `super(DELETE_NODE, ...)`
199
+ # by a user hook, don't want to keep visiting in that case.
200
+ [node, parent]
201
+ else
202
+ # Run hooks if there are any
203
+ new_node = node
204
+ no_hooks = !@visitors.key?(node.class)
205
+ if no_hooks || begin_visit(new_node, parent)
206
+ #{
207
+ if method_defined?(child_visit_method)
208
+ "new_node = #{child_visit_method}(new_node)"
209
+ elsif children_of_type
210
+ children_of_type.map do |child_accessor, child_class|
211
+ "node.#{child_accessor}.each do |child_node|
212
+ new_child_and_node = #{child_class.visit_method}_with_modifications(child_node, new_node)
213
+ # Reassign `node` in case the child hook makes a modification
214
+ if new_child_and_node.is_a?(Array)
215
+ new_node = new_child_and_node[1]
216
+ end
217
+ end"
218
+ end.join("\n")
219
+ else
220
+ ""
221
+ end
222
+ }
223
+ end
224
+ end_visit(new_node, parent) unless no_hooks
225
+ if new_node.equal?(node)
226
+ [node, parent]
227
+ else
228
+ [new_node, parent]
229
+ end
230
+ end
231
+ end
232
+ def #{node_method}_with_modifications(node, parent)
233
+ new_node_and_new_parent = #{node_method}(node, parent)
234
+ apply_modifications(node, parent, new_node_and_new_parent)
235
+ end
236
+ RUBY
237
+ end
238
+
239
+
240
+
240
241
  [
241
242
  Language::Nodes::Argument,
242
243
  Language::Nodes::Directive,
@@ -277,6 +278,8 @@ module GraphQL
277
278
  make_visit_methods(ast_node_class)
278
279
  end
279
280
 
281
+ # rubocop:enable Development/NoEvalCop
282
+
280
283
  private
281
284
 
282
285
  def apply_modifications(node, parent, new_node_and_new_parent)
@@ -227,7 +227,8 @@ module GraphQL
227
227
  current_path
228
228
  else
229
229
  (current_runtime_state = Thread.current[:__graphql_runtime_info]) &&
230
- (current_runtime_state.public_send(key))
230
+ (query_runtime_state = current_runtime_state[@query]) &&
231
+ (query_runtime_state.public_send(key))
231
232
  end
232
233
  else
233
234
  # not found
@@ -237,10 +238,12 @@ module GraphQL
237
238
 
238
239
  def current_path
239
240
  current_runtime_state = Thread.current[:__graphql_runtime_info]
240
- path = current_runtime_state &&
241
- (result = current_runtime_state.current_result) &&
241
+ query_runtime_state = current_runtime_state && current_runtime_state[@query]
242
+
243
+ path = query_runtime_state &&
244
+ (result = query_runtime_state.current_result) &&
242
245
  (result.path)
243
- if path && (rn = current_runtime_state.current_result_name)
246
+ if path && (rn = query_runtime_state.current_result_name)
244
247
  path = path.dup
245
248
  path.push(rn)
246
249
  end
@@ -260,7 +263,8 @@ module GraphQL
260
263
  def fetch(key, default = UNSPECIFIED_FETCH_DEFAULT)
261
264
  if RUNTIME_METADATA_KEYS.include?(key)
262
265
  (runtime = Thread.current[:__graphql_runtime_info]) &&
263
- (runtime.public_send(key))
266
+ (query_runtime_state = runtime[@query]) &&
267
+ (query_runtime_state.public_send(key))
264
268
  elsif @scoped_context.key?(key)
265
269
  scoped_context[key]
266
270
  elsif @provided_values.key?(key)
@@ -277,8 +281,13 @@ module GraphQL
277
281
  def dig(key, *other_keys)
278
282
  if RUNTIME_METADATA_KEYS.include?(key)
279
283
  (current_runtime_state = Thread.current[:__graphql_runtime_info]) &&
280
- (obj = current_runtime_state.public_send(key)) &&
281
- obj.dig(*other_keys)
284
+ (query_runtime_state = current_runtime_state[@query]) &&
285
+ (obj = query_runtime_state.public_send(key)) &&
286
+ if other_keys.empty?
287
+ obj
288
+ else
289
+ obj.dig(*other_keys)
290
+ end
282
291
  elsif @scoped_context.key?(key)
283
292
  @scoped_context.dig(key, *other_keys)
284
293
  else
@@ -3,35 +3,27 @@ module GraphQL
3
3
  class Query
4
4
  # This object can be `ctx` in places where there is no query
5
5
  class NullContext
6
- class NullWarden < GraphQL::Schema::Warden
7
- def visible_field?(field, ctx); true; end
8
- def visible_argument?(arg, ctx); true; end
9
- def visible_type?(type, ctx); true; end
10
- def visible_enum_value?(ev, ctx); true; end
11
- def visible_type_membership?(tm, ctx); true; end
12
- end
13
-
14
6
  class NullQuery
7
+ def after_lazy(value)
8
+ yield(value)
9
+ end
15
10
  end
16
11
 
17
12
  class NullSchema < GraphQL::Schema
18
13
  end
19
14
 
15
+ extend Forwardable
16
+
20
17
  attr_reader :schema, :query, :warden, :dataloader
18
+ def_delegators GraphQL::EmptyObjects::EMPTY_HASH, :[], :fetch, :dig, :key?
21
19
 
22
20
  def initialize
23
21
  @query = NullQuery.new
24
22
  @dataloader = GraphQL::Dataloader::NullDataloader.new
25
23
  @schema = NullSchema
26
- @warden = NullWarden.new(
27
- GraphQL::Filter.new(silence_deprecation_warning: true),
28
- context: self,
29
- schema: @schema,
30
- )
24
+ @warden = Schema::Warden::NullWarden.new(context: self, schema: @schema)
31
25
  end
32
26
 
33
- def [](key); end
34
-
35
27
  def interpreter?
36
28
  true
37
29
  end
@@ -39,13 +31,11 @@ module GraphQL
39
31
  class << self
40
32
  extend Forwardable
41
33
 
42
- def [](key); end
43
-
44
34
  def instance
45
35
  @instance ||= self.new
46
36
  end
47
37
 
48
- def_delegators :instance, :query, :warden, :schema, :interpreter?, :dataloader
38
+ def_delegators :instance, :query, :warden, :schema, :interpreter?, :dataloader, :[], :fetch, :dig, :key?
49
39
  end
50
40
  end
51
41
  end
@@ -68,7 +68,8 @@ module GraphQL
68
68
  elsif @operation_name_error
69
69
  @validation_errors << @operation_name_error
70
70
  else
71
- validation_result = @schema.static_validator.validate(@query, validate: @query.validate, timeout: @schema.validate_timeout, max_errors: @schema.validate_max_errors)
71
+ validator = @query.static_validator || @schema.static_validator
72
+ validation_result = validator.validate(@query, validate: @query.validate, timeout: @schema.validate_timeout, max_errors: @schema.validate_max_errors)
72
73
  @validation_errors.concat(validation_result[:errors])
73
74
 
74
75
  if @validation_errors.empty?
data/lib/graphql/query.rb CHANGED
@@ -45,6 +45,20 @@ module GraphQL
45
45
  end
46
46
  end
47
47
 
48
+ # @return [GraphQL::StaticValidation::Validator] if present, the query will validate with these rules.
49
+ attr_reader :static_validator
50
+
51
+ # @param new_validate [GraphQL::StaticValidation::Validator] if present, the query will validate with these rules. This can't be reasssigned after validation.
52
+ def static_validator=(new_validator)
53
+ if defined?(@validation_pipeline) && @validation_pipeline && @validation_pipeline.has_validated?
54
+ raise ArgumentError, "Can't reassign Query#static_validator= after validation has run, remove this assignment."
55
+ elsif !new_validator.is_a?(GraphQL::StaticValidation::Validator)
56
+ raise ArgumentError, "Expected a `GraphQL::StaticValidation::Validator` instance."
57
+ else
58
+ @static_validator = new_validator
59
+ end
60
+ end
61
+
48
62
  attr_writer :query_string
49
63
 
50
64
  # @return [GraphQL::Language::Nodes::Document]
@@ -83,11 +97,13 @@ module GraphQL
83
97
  # @param max_complexity [Numeric] the maximum field complexity for this query (falls back to schema-level value)
84
98
  # @param except [<#call(schema_member, context)>] If provided, objects will be hidden from the schema when `.call(schema_member, context)` returns truthy
85
99
  # @param only [<#call(schema_member, context)>] If provided, objects will be hidden from the schema when `.call(schema_member, context)` returns false
86
- def initialize(schema, query_string = nil, query: nil, document: nil, context: nil, variables: nil, validate: true, subscription_topic: nil, operation_name: nil, root_value: nil, max_depth: schema.max_depth, max_complexity: schema.max_complexity, except: nil, only: nil, warden: nil)
100
+ def initialize(schema, query_string = nil, query: nil, document: nil, context: nil, variables: nil, validate: true, static_validator: nil, subscription_topic: nil, operation_name: nil, root_value: nil, max_depth: schema.max_depth, max_complexity: schema.max_complexity, except: nil, only: nil, warden: nil)
87
101
  # Even if `variables: nil` is passed, use an empty hash for simpler logic
88
102
  variables ||= {}
89
103
  @schema = schema
90
- @filter = schema.default_filter.merge(except: except, only: only)
104
+ if only || except
105
+ merge_filters(except: except, only: only)
106
+ end
91
107
  @context = schema.context_class.new(query: self, object: root_value, values: context)
92
108
  @warden = warden
93
109
  @subscription_topic = subscription_topic
@@ -95,12 +111,13 @@ module GraphQL
95
111
  @fragments = nil
96
112
  @operations = nil
97
113
  @validate = validate
114
+ self.static_validator = static_validator if static_validator
98
115
  context_tracers = (context ? context.fetch(:tracers, []) : [])
99
116
  @tracers = schema.tracers + context_tracers
100
117
 
101
118
  # Support `ctx[:backtrace] = true` for wrapping backtraces
102
119
  if context && context[:backtrace] && !@tracers.include?(GraphQL::Backtrace::Tracer)
103
- if schema.trace_class <= GraphQL::Tracing::LegacyTrace
120
+ if schema.trace_class <= GraphQL::Tracing::CallLegacyTracers
104
121
  context_tracers += [GraphQL::Backtrace::Tracer]
105
122
  @tracers << GraphQL::Backtrace::Tracer
106
123
  elsif !(current_trace.class <= GraphQL::Backtrace::Trace)
@@ -108,8 +125,8 @@ module GraphQL
108
125
  end
109
126
  end
110
127
 
111
- if context_tracers.any? && !(schema.trace_class <= GraphQL::Tracing::LegacyTrace)
112
- raise ArgumentError, "context[:tracers] are not supported without `trace_class(GraphQL::Tracing::LegacyTrace)` in the schema configuration, please add it."
128
+ if context_tracers.any? && !(schema.trace_class <= GraphQL::Tracing::CallLegacyTracers)
129
+ raise ArgumentError, "context[:tracers] are not supported without `trace_with(GraphQL::Tracing::CallLegacyTracers)` in the schema configuration, please add it."
113
130
  end
114
131
 
115
132
 
@@ -151,11 +168,6 @@ module GraphQL
151
168
 
152
169
  @result_values = nil
153
170
  @executed = false
154
-
155
- # TODO add a general way to define schema-level filters
156
- if @schema.respond_to?(:visible?)
157
- merge_filters(only: @schema.method(:visible?))
158
- end
159
171
  end
160
172
 
161
173
  # If a document was provided to `GraphQL::Schema#execute` instead of the raw query string, we will need to get it from the document
@@ -171,7 +183,7 @@ module GraphQL
171
183
 
172
184
  # @return [GraphQL::Tracing::Trace]
173
185
  def current_trace
174
- @current_trace ||= multiplex ? multiplex.current_trace : schema.new_trace(multiplex: multiplex, query: self)
186
+ @current_trace ||= context[:trace] || (multiplex ? multiplex.current_trace : schema.new_trace(multiplex: multiplex, query: self))
175
187
  end
176
188
 
177
189
  def subscription_update?
@@ -347,6 +359,7 @@ module GraphQL
347
359
  if @prepared_ast
348
360
  raise "Can't add filters after preparing the query"
349
361
  else
362
+ @filter ||= @schema.default_filter
350
363
  @filter = @filter.merge(only: only, except: except)
351
364
  end
352
365
  nil
@@ -361,6 +374,18 @@ module GraphQL
361
374
  schema.handle_or_reraise(context, err)
362
375
  end
363
376
 
377
+ def after_lazy(value, &block)
378
+ if !defined?(@runtime_instance)
379
+ @runtime_instance = context.namespace(:interpreter_runtime)[:runtime]
380
+ end
381
+
382
+ if @runtime_instance
383
+ @runtime_instance.minimal_after_lazy(value, &block)
384
+ else
385
+ @schema.after_lazy(value, &block)
386
+ end
387
+ end
388
+
364
389
  private
365
390
 
366
391
  def find_operation(operations, operation_name)
@@ -375,7 +400,7 @@ module GraphQL
375
400
 
376
401
  def prepare_ast
377
402
  @prepared_ast = true
378
- @warden ||= GraphQL::Schema::Warden.new(@filter, schema: @schema, context: @context)
403
+ @warden ||= @schema.warden_class.new(@filter, schema: @schema, context: @context)
379
404
  parse_error = nil
380
405
  @document ||= begin
381
406
  if query_string
@@ -40,14 +40,21 @@ module GraphQL
40
40
  end
41
41
 
42
42
  def add_directives_from(owner)
43
- dirs = owner.directives.map(&:class)
44
- @directives.merge(dirs)
45
- add_type_and_traverse(dirs)
43
+ if (dir_instances = owner.directives).any?
44
+ dirs = dir_instances.map(&:class)
45
+ @directives.merge(dirs)
46
+ add_type_and_traverse(dirs)
47
+ end
46
48
  end
47
49
 
48
50
  def add_type_and_traverse(new_types)
49
51
  late_types = []
50
- new_types.each { |t| add_type(t, owner: nil, late_types: late_types, path: [t.graphql_name]) }
52
+ path = []
53
+ new_types.each do |t|
54
+ path.push(t.graphql_name)
55
+ add_type(t, owner: nil, late_types: late_types, path: path)
56
+ path.pop
57
+ end
51
58
  missed_late_types = 0
52
59
  while (late_type_vals = late_types.shift)
53
60
  type_owner, lt = late_type_vals
@@ -158,7 +165,9 @@ module GraphQL
158
165
  type.all_argument_definitions.each do |arg|
159
166
  arg_type = arg.type.unwrap
160
167
  references_to(arg_type, from: arg)
161
- add_type(arg_type, owner: arg, late_types: late_types, path: path + [arg.graphql_name])
168
+ path.push(arg.graphql_name)
169
+ add_type(arg_type, owner: arg, late_types: late_types, path: path)
170
+ path.pop
162
171
  if arg.default_value?
163
172
  @arguments_with_default_values << arg
164
173
  end
@@ -179,18 +188,21 @@ module GraphQL
179
188
  name = field.graphql_name
180
189
  field_type = field.type.unwrap
181
190
  references_to(field_type, from: field)
182
- field_path = path + [name]
183
- add_type(field_type, owner: field, late_types: late_types, path: field_path)
191
+ path.push(name)
192
+ add_type(field_type, owner: field, late_types: late_types, path: path)
184
193
  add_directives_from(field)
185
194
  field.all_argument_definitions.each do |arg|
186
195
  add_directives_from(arg)
187
196
  arg_type = arg.type.unwrap
188
197
  references_to(arg_type, from: arg)
189
- add_type(arg_type, owner: arg, late_types: late_types, path: field_path + [arg.graphql_name])
198
+ path.push(arg.graphql_name)
199
+ add_type(arg_type, owner: arg, late_types: late_types, path: path)
200
+ path.pop
190
201
  if arg.default_value?
191
202
  @arguments_with_default_values << arg
192
203
  end
193
204
  end
205
+ path.pop
194
206
  end
195
207
  end
196
208
  if type.kind.input_object?
@@ -198,7 +210,9 @@ module GraphQL
198
210
  add_directives_from(arg)
199
211
  arg_type = arg.type.unwrap
200
212
  references_to(arg_type, from: arg)
201
- add_type(arg_type, owner: arg, late_types: late_types, path: path + [arg.graphql_name])
213
+ path.push(arg.graphql_name)
214
+ add_type(arg_type, owner: arg, late_types: late_types, path: path)
215
+ path.pop
202
216
  if arg.default_value?
203
217
  @arguments_with_default_values << arg
204
218
  end
@@ -206,14 +220,18 @@ module GraphQL
206
220
  end
207
221
  if type.kind.union?
208
222
  @possible_types[type.graphql_name] = type.all_possible_types
223
+ path.push("possible_types")
209
224
  type.all_possible_types.each do |t|
210
- add_type(t, owner: type, late_types: late_types, path: path + ["possible_types"])
225
+ add_type(t, owner: type, late_types: late_types, path: path)
211
226
  end
227
+ path.pop
212
228
  end
213
229
  if type.kind.interface?
230
+ path.push("orphan_types")
214
231
  type.orphan_types.each do |t|
215
- add_type(t, owner: type, late_types: late_types, path: path + ["orphan_types"])
232
+ add_type(t, owner: type, late_types: late_types, path: path)
216
233
  end
234
+ path.pop
217
235
  end
218
236
  if type.kind.object?
219
237
  possible_types_for_this_name = @possible_types[type.graphql_name] ||= []
@@ -221,6 +239,7 @@ module GraphQL
221
239
  end
222
240
 
223
241
  if type.kind.object? || type.kind.interface?
242
+ path.push("implements")
224
243
  type.interface_type_memberships.each do |interface_type_membership|
225
244
  case interface_type_membership
226
245
  when Schema::TypeMembership
@@ -235,7 +254,14 @@ module GraphQL
235
254
  else
236
255
  raise ArgumentError, "Invariant: unexpected type membership for #{type.graphql_name}: #{interface_type_membership.class} (#{interface_type_membership.inspect})"
237
256
  end
238
- add_type(interface_type, owner: type, late_types: late_types, path: path + ["implements"])
257
+ add_type(interface_type, owner: type, late_types: late_types, path: path)
258
+ end
259
+ path.pop
260
+ end
261
+
262
+ if type.kind.enum?
263
+ type.all_enum_value_definitions.each do |value_definition|
264
+ add_directives_from(value_definition)
239
265
  end
240
266
  end
241
267
  end
@@ -0,0 +1,10 @@
1
+ # frozen_string_literal: true
2
+ module GraphQL
3
+ class Schema
4
+ class AlwaysVisible
5
+ def self.use(schema, **opts)
6
+ schema.warden_class = GraphQL::Schema::Warden::NullWarden
7
+ end
8
+ end
9
+ end
10
+ end