graphql 1.12.21 → 1.13.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (99) hide show
  1. checksums.yaml +4 -4
  2. data/lib/generators/graphql/mutation_generator.rb +1 -1
  3. data/lib/generators/graphql/type_generator.rb +0 -1
  4. data/lib/graphql/analysis/ast/field_usage.rb +2 -2
  5. data/lib/graphql/analysis/ast/query_complexity.rb +10 -14
  6. data/lib/graphql/analysis/ast/visitor.rb +4 -4
  7. data/lib/graphql/backtrace/table.rb +1 -1
  8. data/lib/graphql/dataloader.rb +55 -22
  9. data/lib/graphql/directive.rb +0 -4
  10. data/lib/graphql/enum_type.rb +5 -1
  11. data/lib/graphql/execution/errors.rb +1 -0
  12. data/lib/graphql/execution/interpreter/arguments.rb +1 -1
  13. data/lib/graphql/execution/interpreter/arguments_cache.rb +2 -2
  14. data/lib/graphql/execution/interpreter/runtime.rb +20 -12
  15. data/lib/graphql/execution/lookahead.rb +2 -2
  16. data/lib/graphql/execution/multiplex.rb +1 -1
  17. data/lib/graphql/introspection/directive_type.rb +1 -1
  18. data/lib/graphql/introspection/entry_points.rb +2 -2
  19. data/lib/graphql/introspection/enum_value_type.rb +2 -2
  20. data/lib/graphql/introspection/field_type.rb +2 -2
  21. data/lib/graphql/introspection/input_value_type.rb +4 -4
  22. data/lib/graphql/introspection/schema_type.rb +2 -2
  23. data/lib/graphql/introspection/type_type.rb +10 -10
  24. data/lib/graphql/language/block_string.rb +0 -4
  25. data/lib/graphql/language/document_from_schema_definition.rb +4 -2
  26. data/lib/graphql/language/lexer.rb +0 -3
  27. data/lib/graphql/language/lexer.rl +0 -4
  28. data/lib/graphql/language/nodes.rb +2 -1
  29. data/lib/graphql/language/parser.rb +442 -434
  30. data/lib/graphql/language/parser.y +5 -4
  31. data/lib/graphql/language/printer.rb +6 -1
  32. data/lib/graphql/language/sanitized_printer.rb +5 -5
  33. data/lib/graphql/language/token.rb +0 -4
  34. data/lib/graphql/name_validator.rb +0 -4
  35. data/lib/graphql/query/arguments.rb +1 -1
  36. data/lib/graphql/query/arguments_cache.rb +1 -1
  37. data/lib/graphql/query/context.rb +5 -2
  38. data/lib/graphql/query/literal_input.rb +1 -1
  39. data/lib/graphql/query/null_context.rb +12 -7
  40. data/lib/graphql/query/serial_execution/field_resolution.rb +1 -1
  41. data/lib/graphql/query/variables.rb +5 -1
  42. data/lib/graphql/relay/edges_instrumentation.rb +0 -1
  43. data/lib/graphql/rubocop/graphql/base_cop.rb +36 -0
  44. data/lib/graphql/rubocop/graphql/default_null_true.rb +43 -0
  45. data/lib/graphql/rubocop/graphql/default_required_true.rb +43 -0
  46. data/lib/graphql/rubocop.rb +4 -0
  47. data/lib/graphql/schema/addition.rb +37 -28
  48. data/lib/graphql/schema/argument.rb +6 -6
  49. data/lib/graphql/schema/build_from_definition.rb +5 -5
  50. data/lib/graphql/schema/directive/feature.rb +1 -1
  51. data/lib/graphql/schema/directive/flagged.rb +2 -2
  52. data/lib/graphql/schema/directive/include.rb +1 -1
  53. data/lib/graphql/schema/directive/skip.rb +1 -1
  54. data/lib/graphql/schema/directive/transform.rb +1 -1
  55. data/lib/graphql/schema/directive.rb +2 -2
  56. data/lib/graphql/schema/enum.rb +57 -9
  57. data/lib/graphql/schema/enum_value.rb +4 -0
  58. data/lib/graphql/schema/field/connection_extension.rb +1 -1
  59. data/lib/graphql/schema/field.rb +92 -17
  60. data/lib/graphql/schema/find_inherited_value.rb +1 -0
  61. data/lib/graphql/schema/finder.rb +5 -5
  62. data/lib/graphql/schema/input_object.rb +6 -5
  63. data/lib/graphql/schema/interface.rb +8 -19
  64. data/lib/graphql/schema/member/accepts_definition.rb +8 -1
  65. data/lib/graphql/schema/member/build_type.rb +0 -4
  66. data/lib/graphql/schema/member/has_arguments.rb +55 -13
  67. data/lib/graphql/schema/member/has_deprecation_reason.rb +1 -1
  68. data/lib/graphql/schema/member/has_fields.rb +76 -18
  69. data/lib/graphql/schema/member/has_interfaces.rb +90 -0
  70. data/lib/graphql/schema/member.rb +1 -0
  71. data/lib/graphql/schema/object.rb +7 -74
  72. data/lib/graphql/schema/printer.rb +1 -1
  73. data/lib/graphql/schema/relay_classic_mutation.rb +29 -3
  74. data/lib/graphql/schema/resolver/has_payload_type.rb +27 -2
  75. data/lib/graphql/schema/resolver.rb +19 -5
  76. data/lib/graphql/schema/subscription.rb +11 -1
  77. data/lib/graphql/schema/type_expression.rb +1 -1
  78. data/lib/graphql/schema/type_membership.rb +18 -4
  79. data/lib/graphql/schema/union.rb +6 -1
  80. data/lib/graphql/schema/validator/format_validator.rb +0 -4
  81. data/lib/graphql/schema/validator/numericality_validator.rb +1 -0
  82. data/lib/graphql/schema/warden.rb +116 -52
  83. data/lib/graphql/schema.rb +87 -15
  84. data/lib/graphql/static_validation/base_visitor.rb +5 -5
  85. data/lib/graphql/static_validation/definition_dependencies.rb +0 -1
  86. data/lib/graphql/static_validation/literal_validator.rb +1 -1
  87. data/lib/graphql/static_validation/rules/argument_literals_are_compatible.rb +1 -1
  88. data/lib/graphql/static_validation/rules/fields_will_merge.rb +1 -1
  89. data/lib/graphql/static_validation/rules/required_arguments_are_present.rb +1 -1
  90. data/lib/graphql/static_validation/rules/required_input_object_attributes_are_present.rb +4 -4
  91. data/lib/graphql/static_validation/rules/variable_usages_are_allowed.rb +7 -7
  92. data/lib/graphql/subscriptions/action_cable_subscriptions.rb +6 -4
  93. data/lib/graphql/subscriptions/event.rb +20 -12
  94. data/lib/graphql/subscriptions.rb +17 -19
  95. data/lib/graphql/types/relay/has_node_field.rb +1 -1
  96. data/lib/graphql/types/relay/has_nodes_field.rb +1 -1
  97. data/lib/graphql/version.rb +1 -1
  98. data/lib/graphql.rb +9 -31
  99. metadata +10 -5
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 6fa9800286687f6236697bf1f3eed4f3342b40fbbbebc64c472a7d791442bce4
4
- data.tar.gz: a74ed6cf70cf2f626c2339a8377ada5dea5491eb3e53a1e1783b4a7a8dd8bebc
3
+ metadata.gz: 853fa0482ef0c3bafe04dce77dff9bb685633a1e4c273fd234169f98d595352c
4
+ data.tar.gz: 6cf800af8dfc469f4d7a375ee22f6d98e03207799f813f10176916f09a0a4064
5
5
  SHA512:
6
- metadata.gz: 41c6592dbd0cd27e82f036f271c71098a14c2b10d7cc700fc680caa1133b0a148a730b9e15d5a4d04c98f72bfd4a418d8ae63b09f327193f80af2220fc399fc0
7
- data.tar.gz: cb35e9d298bc92431ae561e8c663c00fcf899c1cc1c1daca9730717ba6636f9eb177af40b1314e55f73a411d2a78eeaadc2d2c6b34b583cd3fbe7525d18a8139
6
+ metadata.gz: 7bcd2b94fa64ab65fb47995a4896b08629bfc9b66f7797dfd4959ad8ccdb5332bf63ae49f5139c7d1766b3d72cb500da257c611e628dc5db36ae26b472c5d51c
7
+ data.tar.gz: 51a5c6791429c17940d8d0a5407efb852fd4ddbe7a5eaf706dd8fb074a6654f17b32b08f21956e4e450dff6cff05fb0020a7ff8a141fe38f3e09b8433ca1b4ea
@@ -17,7 +17,7 @@ module Graphql
17
17
 
18
18
  argument :name, type: :string
19
19
 
20
- def initialize(args, *options) #:nodoc:
20
+ def initialize(args, *options) # :nodoc:
21
21
  # Unfreeze name in case it's given as a frozen string
22
22
  args[0] = args[0].dup if args[0].is_a?(String) && args[0].frozen?
23
23
  super
@@ -13,7 +13,6 @@ module Graphql
13
13
 
14
14
  argument :type_name,
15
15
  type: :string,
16
- required: true,
17
16
  banner: "TypeName",
18
17
  desc: "Name of this object type (expressed as Ruby or GraphQL)"
19
18
 
@@ -36,12 +36,12 @@ module GraphQL
36
36
  end
37
37
 
38
38
  if argument.definition.type.kind.input_object?
39
- extract_deprecated_arguments(argument.value.arguments.argument_values)
39
+ extract_deprecated_arguments(argument.value.arguments.argument_values) # rubocop:disable Development/ContextIsPassedCop -- runtime args instance
40
40
  elsif argument.definition.type.list? && !argument.value.nil?
41
41
  argument
42
42
  .value
43
43
  .select { |value| value.respond_to?(:arguments) }
44
- .each { |value| extract_deprecated_arguments(value.arguments.argument_values) }
44
+ .each { |value| extract_deprecated_arguments(value.arguments.argument_values) } # rubocop:disable Development/ContextIsPassedCop -- runtime args instance
45
45
  end
46
46
  end
47
47
  end
@@ -23,18 +23,22 @@ module GraphQL
23
23
 
24
24
  attr_reader :field_definition, :response_path, :query
25
25
 
26
- # @param node [Language::Nodes::Field] The AST node; used for providing argument values when necessary
26
+ # @param parent_type [Class] The owner of `field_definition`
27
27
  # @param field_definition [GraphQL::Field, GraphQL::Schema::Field] Used for getting the `.complexity` configuration
28
28
  # @param query [GraphQL::Query] Used for `query.possible_types`
29
29
  # @param response_path [Array<String>] The path to the response key for the field
30
- def initialize(node, field_definition, query, response_path)
31
- @node = node
30
+ def initialize(parent_type, field_definition, query, response_path)
31
+ @parent_type = parent_type
32
32
  @field_definition = field_definition
33
33
  @query = query
34
34
  @response_path = response_path
35
35
  @scoped_children = nil
36
+ @nodes = []
36
37
  end
37
38
 
39
+ # @return [Array<GraphQL::Language::Nodes::Field>]
40
+ attr_reader :nodes
41
+
38
42
  # Returns true if this field has no selections, ie, it's a scalar.
39
43
  # We need a quick way to check whether we should continue traversing.
40
44
  def terminal?
@@ -50,16 +54,7 @@ module GraphQL
50
54
  end
51
55
 
52
56
  def own_complexity(child_complexity)
53
- defined_complexity = @field_definition.complexity
54
- case defined_complexity
55
- when Proc
56
- arguments = @query.arguments_for(@node, @field_definition)
57
- defined_complexity.call(@query.context, arguments.keyword_arguments, child_complexity)
58
- when Numeric
59
- defined_complexity + child_complexity
60
- else
61
- raise("Invalid complexity: #{defined_complexity.inspect} on #{@field_definition.name}")
62
- end
57
+ @field_definition.calculate_complexity(query: @query, nodes: @nodes, child_complexity: child_complexity)
63
58
  end
64
59
  end
65
60
 
@@ -79,7 +74,8 @@ module GraphQL
79
74
  # then the query would have been rejected as invalid.
80
75
  complexities_on_type = @complexities_on_type_by_query[visitor.query] ||= [ScopedTypeComplexity.new(nil, nil, query, visitor.response_path)]
81
76
 
82
- complexity = complexities_on_type.last.scoped_children[parent_type][field_key] ||= ScopedTypeComplexity.new(node, visitor.field_definition, visitor.query, visitor.response_path)
77
+ complexity = complexities_on_type.last.scoped_children[parent_type][field_key] ||= ScopedTypeComplexity.new(parent_type, visitor.field_definition, visitor.query, visitor.response_path)
78
+ complexity.nodes.push(node)
83
79
  # Push it on the stack.
84
80
  complexities_on_type.push(complexity)
85
81
  end
@@ -100,7 +100,7 @@ module GraphQL
100
100
  def on_field(node, parent)
101
101
  @response_path.push(node.alias || node.name)
102
102
  parent_type = @object_types.last
103
- field_definition = @schema.get_field(parent_type, node.name)
103
+ field_definition = @schema.get_field(parent_type, node.name, @query.context)
104
104
  @field_definitions.push(field_definition)
105
105
  if !field_definition.nil?
106
106
  next_object_type = field_definition.type.unwrap
@@ -138,14 +138,14 @@ module GraphQL
138
138
  argument_defn = if (arg = @argument_definitions.last)
139
139
  arg_type = arg.type.unwrap
140
140
  if arg_type.kind.input_object?
141
- arg_type.arguments[node.name]
141
+ arg_type.get_argument(node.name, @query.context)
142
142
  else
143
143
  nil
144
144
  end
145
145
  elsif (directive_defn = @directive_definitions.last)
146
- directive_defn.arguments[node.name]
146
+ directive_defn.get_argument(node.name, @query.context)
147
147
  elsif (field_defn = @field_definitions.last)
148
- field_defn.arguments[node.name]
148
+ field_defn.get_argument(node.name, @query.context)
149
149
  else
150
150
  nil
151
151
  end
@@ -89,7 +89,7 @@ module GraphQL
89
89
  "#{context_entry.ast_node ? context_entry.ast_node.position.join(":") : ""}",
90
90
  "#{context_entry.field.path}#{field_alias ? " as #{field_alias}" : ""}",
91
91
  "#{context_entry.object.object.inspect}",
92
- context_entry.arguments.to_h.inspect,
92
+ context_entry.arguments.to_h.inspect, # rubocop:disable Development/ContextIsPassedCop -- unrelated method
93
93
  Backtrace::InspectResult.inspect_result(value),
94
94
  ]
95
95
  if (parent = context_entry.parent_frame)
@@ -23,8 +23,18 @@ module GraphQL
23
23
  # end
24
24
  #
25
25
  class Dataloader
26
- def self.use(schema)
27
- schema.dataloader_class = self
26
+ class << self
27
+ attr_accessor :default_nonblocking
28
+ end
29
+
30
+ AsyncDataloader = Class.new(self) { self.default_nonblocking = true }
31
+
32
+ def self.use(schema, nonblocking: nil)
33
+ schema.dataloader_class = if nonblocking
34
+ AsyncDataloader
35
+ else
36
+ self
37
+ end
28
38
  end
29
39
 
30
40
  # Call the block with a Dataloader instance,
@@ -39,9 +49,16 @@ module GraphQL
39
49
  result
40
50
  end
41
51
 
42
- def initialize
52
+ def initialize(nonblocking: self.class.default_nonblocking)
43
53
  @source_cache = Hash.new { |h, k| h[k] = {} }
44
54
  @pending_jobs = []
55
+ if !nonblocking.nil?
56
+ @nonblocking = nonblocking
57
+ end
58
+ end
59
+
60
+ def nonblocking?
61
+ @nonblocking
45
62
  end
46
63
 
47
64
  # Get a Source instance from this dataloader, for calling `.load(...)` or `.request(...)` on.
@@ -50,7 +67,7 @@ module GraphQL
50
67
  # @param batch_parameters [Array<Object>]
51
68
  # @return [GraphQL::Dataloader::Source] An instance of {source_class}, initialized with `self, *batch_parameters`,
52
69
  # and cached for the lifetime of this {Multiplex}.
53
- if RUBY_VERSION < "3"
70
+ if RUBY_VERSION < "3" || RUBY_ENGINE != "ruby" # truffle-ruby wasn't doing well with the implementation below
54
71
  def with(source_class, *batch_args)
55
72
  batch_key = source_class.batch_key_for(*batch_args)
56
73
  @source_cache[source_class][batch_key] ||= begin
@@ -117,6 +134,9 @@ module GraphQL
117
134
 
118
135
  # @api private Move along, move along
119
136
  def run
137
+ if @nonblocking && !Fiber.scheduler
138
+ raise "`nonblocking: true` requires `Fiber.scheduler`, assign one with `Fiber.set_scheduler(...)` before executing GraphQL."
139
+ end
120
140
  # At a high level, the algorithm is:
121
141
  #
122
142
  # A) Inside Fibers, run jobs from the queue one-by-one
@@ -137,6 +157,8 @@ module GraphQL
137
157
  #
138
158
  pending_fibers = []
139
159
  next_fibers = []
160
+ pending_source_fibers = []
161
+ next_source_fibers = []
140
162
  first_pass = true
141
163
 
142
164
  while first_pass || (f = pending_fibers.shift)
@@ -174,31 +196,27 @@ module GraphQL
174
196
  # This is where an evented approach would be even better -- can we tell which
175
197
  # fibers are ready to continue, and continue execution there?
176
198
  #
177
- source_fiber_queue = if (first_source_fiber = create_source_fiber)
178
- [first_source_fiber]
179
- else
180
- nil
199
+ if (first_source_fiber = create_source_fiber)
200
+ pending_source_fibers << first_source_fiber
181
201
  end
182
202
 
183
- if source_fiber_queue
184
- while (outer_source_fiber = source_fiber_queue.shift)
203
+ while pending_source_fibers.any?
204
+ while (outer_source_fiber = pending_source_fibers.pop)
185
205
  resume(outer_source_fiber)
186
-
187
- # If this source caused more sources to become pending, run those before running this one again:
188
- next_source_fiber = create_source_fiber
189
- if next_source_fiber
190
- source_fiber_queue << next_source_fiber
191
- end
192
-
193
206
  if outer_source_fiber.alive?
194
- source_fiber_queue << outer_source_fiber
207
+ next_source_fibers << outer_source_fiber
208
+ end
209
+ if (next_source_fiber = create_source_fiber)
210
+ pending_source_fibers << next_source_fiber
195
211
  end
196
212
  end
213
+ join_queues(pending_source_fibers, next_source_fibers)
214
+ next_source_fibers.clear
197
215
  end
198
216
  # Move newly-enqueued Fibers on to the list to be resumed.
199
217
  # Clear out the list of next-round Fibers, so that
200
218
  # any Fibers that pause can be put on it.
201
- pending_fibers.concat(next_fibers)
219
+ join_queues(pending_fibers, next_fibers)
202
220
  next_fibers.clear
203
221
  end
204
222
  end
@@ -213,6 +231,14 @@ module GraphQL
213
231
  nil
214
232
  end
215
233
 
234
+ def join_queues(previous_queue, next_queue)
235
+ if @nonblocking
236
+ Fiber.scheduler.run
237
+ next_queue.select!(&:alive?)
238
+ end
239
+ previous_queue.concat(next_queue)
240
+ end
241
+
216
242
  private
217
243
 
218
244
  # If there are pending sources, return a fiber for running them.
@@ -266,9 +292,16 @@ module GraphQL
266
292
  fiber_locals[fiber_var_key] = Thread.current[fiber_var_key]
267
293
  end
268
294
 
269
- Fiber.new do
270
- fiber_locals.each { |k, v| Thread.current[k] = v }
271
- yield
295
+ if @nonblocking
296
+ Fiber.new(blocking: false) do
297
+ fiber_locals.each { |k, v| Thread.current[k] = v }
298
+ yield
299
+ end
300
+ else
301
+ Fiber.new do
302
+ fiber_locals.each { |k, v| Thread.current[k] = v }
303
+ yield
304
+ end
272
305
  end
273
306
  end
274
307
  end
@@ -105,7 +105,3 @@ module GraphQL
105
105
  end
106
106
  end
107
107
  end
108
-
109
- require "graphql/directive/include_directive"
110
- require "graphql/directive/skip_directive"
111
- require "graphql/directive/deprecated_directive"
@@ -34,10 +34,14 @@ module GraphQL
34
34
  end
35
35
 
36
36
  # @return [Hash<String => EnumValue>] `{name => value}` pairs contained in this type
37
- def values
37
+ def values(_context = nil)
38
38
  @values_by_name
39
39
  end
40
40
 
41
+ def enum_values(_context = nil)
42
+ values.values
43
+ end
44
+
41
45
  def kind
42
46
  GraphQL::TypeKinds::ENUM
43
47
  end
@@ -111,6 +111,7 @@ module GraphQL
111
111
  runtime_info = ctx.namespace(:interpreter) || {}
112
112
  obj = runtime_info[:current_object]
113
113
  args = runtime_info[:current_arguments]
114
+ args = args && args.keyword_arguments
114
115
  field = runtime_info[:current_field]
115
116
  if obj.is_a?(GraphQL::Schema::Object)
116
117
  obj = obj.object
@@ -59,7 +59,7 @@ module GraphQL
59
59
  @empty
60
60
  end
61
61
 
62
- def_delegators :keyword_arguments, :key?, :[], :fetch, :keys, :each, :values
62
+ def_delegators :keyword_arguments, :key?, :[], :fetch, :keys, :each, :values, :size, :to_h
63
63
  def_delegators :argument_values, :each_value
64
64
 
65
65
  def inspect
@@ -71,11 +71,11 @@ module GraphQL
71
71
  when Array
72
72
  ast_arg_or_hash_or_value.map { |v| prepare_args_hash(query, v) }
73
73
  when GraphQL::Language::Nodes::Field, GraphQL::Language::Nodes::InputObject, GraphQL::Language::Nodes::Directive
74
- if ast_arg_or_hash_or_value.arguments.empty?
74
+ if ast_arg_or_hash_or_value.arguments.empty? # rubocop:disable Development/ContextIsPassedCop -- AST-related
75
75
  return NO_ARGUMENTS
76
76
  end
77
77
  args_hash = {}
78
- ast_arg_or_hash_or_value.arguments.each do |arg|
78
+ ast_arg_or_hash_or_value.arguments.each do |arg| # rubocop:disable Development/ContextIsPassedCop -- AST-related
79
79
  v = prepare_args_hash(query, arg.value)
80
80
  if v != NO_VALUE_GIVEN
81
81
  args_hash[arg.name] = v
@@ -314,7 +314,7 @@ module GraphQL
314
314
  case node
315
315
  when GraphQL::Language::Nodes::InlineFragment
316
316
  if node.type
317
- type_defn = schema.get_type(node.type.name)
317
+ type_defn = schema.get_type(node.type.name, context)
318
318
 
319
319
  # Faster than .map{}.include?()
320
320
  query.warden.possible_types(type_defn).each do |t|
@@ -329,7 +329,7 @@ module GraphQL
329
329
  end
330
330
  when GraphQL::Language::Nodes::FragmentSpread
331
331
  fragment_def = query.fragments[node.name]
332
- type_defn = schema.get_type(fragment_def.type.name)
332
+ type_defn = query.get_type(fragment_def.type.name)
333
333
  possible_types = query.warden.possible_types(type_defn)
334
334
  possible_types.each do |t|
335
335
  if t == owner_type
@@ -384,7 +384,9 @@ module GraphQL
384
384
  ast_node = field_ast_nodes_or_ast_node
385
385
  end
386
386
  field_name = ast_node.name
387
- field_defn = @fields_cache[owner_type][field_name] ||= owner_type.get_field(field_name)
387
+ # This can't use `query.get_field` because it gets confused on introspection below if `field_defn` isn't `nil`,
388
+ # because of how `is_introspection` is used to call `.authorized_new` later on.
389
+ field_defn = @fields_cache[owner_type][field_name] ||= owner_type.get_field(field_name, @context)
388
390
  is_introspection = false
389
391
  if field_defn.nil?
390
392
  field_defn = if owner_type == schema.query && (entry_point_field = schema.introspection_system.entry_point(name: field_name))
@@ -419,10 +421,10 @@ module GraphQL
419
421
  object = authorized_new(field_defn.owner, object, context)
420
422
  end
421
423
 
422
- total_args_count = field_defn.arguments.size
424
+ total_args_count = field_defn.arguments(context).size
423
425
  if total_args_count == 0
424
- kwarg_arguments = GraphQL::Execution::Interpreter::Arguments::EMPTY
425
- evaluate_selection_with_args(kwarg_arguments, field_defn, next_path, ast_node, field_ast_nodes, scoped_context, owner_type, object, is_eager_field, result_name, selections_result, parent_object)
426
+ resolved_arguments = GraphQL::Execution::Interpreter::Arguments::EMPTY
427
+ evaluate_selection_with_args(resolved_arguments, field_defn, next_path, ast_node, field_ast_nodes, scoped_context, owner_type, object, is_eager_field, result_name, selections_result, parent_object)
426
428
  else
427
429
  # TODO remove all arguments(...) usages?
428
430
  @query.arguments_cache.dataload_for(ast_node, field_defn, object) do |resolved_arguments|
@@ -431,10 +433,10 @@ module GraphQL
431
433
  end
432
434
  end
433
435
 
434
- def evaluate_selection_with_args(kwarg_arguments, field_defn, next_path, ast_node, field_ast_nodes, scoped_context, owner_type, object, is_eager_field, result_name, selection_result, parent_object) # rubocop:disable Metrics/ParameterLists
436
+ def evaluate_selection_with_args(arguments, field_defn, next_path, ast_node, field_ast_nodes, scoped_context, owner_type, object, is_eager_field, result_name, selection_result, parent_object) # rubocop:disable Metrics/ParameterLists
435
437
  context.scoped_context = scoped_context
436
438
  return_type = field_defn.type
437
- after_lazy(kwarg_arguments, owner: owner_type, field: field_defn, path: next_path, ast_node: ast_node, scoped_context: context.scoped_context, owner_object: object, arguments: kwarg_arguments, result_name: result_name, result: selection_result) do |resolved_arguments|
439
+ after_lazy(arguments, owner: owner_type, field: field_defn, path: next_path, ast_node: ast_node, scoped_context: context.scoped_context, owner_object: object, arguments: arguments, result_name: result_name, result: selection_result) do |resolved_arguments|
438
440
  if resolved_arguments.is_a?(GraphQL::ExecutionError) || resolved_arguments.is_a?(GraphQL::UnauthorizedError)
439
441
  continue_value(next_path, resolved_arguments, owner_type, field_defn, return_type.non_null?, ast_node, result_name, selection_result)
440
442
  next
@@ -485,7 +487,7 @@ module GraphQL
485
487
  resolved_arguments.keyword_arguments
486
488
  end
487
489
 
488
- set_all_interpreter_context(nil, nil, kwarg_arguments, nil)
490
+ set_all_interpreter_context(nil, nil, resolved_arguments, nil)
489
491
 
490
492
  # Optimize for the case that field is selected only once
491
493
  if field_ast_nodes.nil? || field_ast_nodes.size == 1
@@ -511,7 +513,7 @@ module GraphQL
511
513
  rescue GraphQL::ExecutionError => err
512
514
  err
513
515
  end
514
- after_lazy(app_result, owner: owner_type, field: field_defn, path: next_path, ast_node: ast_node, scoped_context: context.scoped_context, owner_object: object, arguments: kwarg_arguments, result_name: result_name, result: selection_result) do |inner_result|
516
+ after_lazy(app_result, owner: owner_type, field: field_defn, path: next_path, ast_node: ast_node, scoped_context: context.scoped_context, owner_object: object, arguments: resolved_arguments, result_name: result_name, result: selection_result) do |inner_result|
515
517
  continue_value = continue_value(next_path, inner_result, owner_type, field_defn, return_type.non_null?, ast_node, result_name, selection_result)
516
518
  if HALT != continue_value
517
519
  continue_field(next_path, continue_value, owner_type, field_defn, return_type, ast_node, next_selections, false, object, kwarg_arguments, result_name, selection_result)
@@ -637,14 +639,20 @@ module GraphQL
637
639
  when Array
638
640
  # It's an array full of execution errors; add them all.
639
641
  if value.any? && value.all? { |v| v.is_a?(GraphQL::ExecutionError) }
642
+ list_type_at_all = (field && (field.type.list?))
640
643
  if selection_result.nil? || !dead_result?(selection_result)
641
644
  value.each_with_index do |error, index|
642
645
  error.ast_node ||= ast_node
643
- error.path ||= path + ((field && field.type.list?) ? [index] : [])
646
+ error.path ||= path + (list_type_at_all ? [index] : [])
644
647
  context.errors << error
645
648
  end
646
649
  if selection_result
647
- set_result(selection_result, result_name, nil)
650
+ if list_type_at_all
651
+ result_without_errors = value.map { |v| v.is_a?(GraphQL::ExecutionError) ? nil : v }
652
+ set_result(selection_result, result_name, result_without_errors)
653
+ else
654
+ set_result(selection_result, result_name, nil)
655
+ end
648
656
  end
649
657
  end
650
658
  HALT
@@ -254,14 +254,14 @@ module GraphQL
254
254
  subselections_on_type = selections_on_type
255
255
  if (t = ast_selection.type)
256
256
  # Assuming this is valid, that `t` will be found.
257
- on_type = @query.schema.get_type(t.name).type_class
257
+ on_type = @query.get_type(t.name).type_class
258
258
  subselections_on_type = subselections_by_type[on_type] ||= {}
259
259
  end
260
260
  find_selections(subselections_by_type, subselections_on_type, on_type, ast_selection.selections, arguments)
261
261
  when GraphQL::Language::Nodes::FragmentSpread
262
262
  frag_defn = @query.fragments[ast_selection.name] || raise("Invariant: Can't look ahead to nonexistent fragment #{ast_selection.name} (found: #{@query.fragments.keys})")
263
263
  # Again, assuming a valid AST
264
- on_type = @query.schema.get_type(frag_defn.type.name).type_class
264
+ on_type = @query.get_type(frag_defn.type.name).type_class
265
265
  subselections_on_type = subselections_by_type[on_type] ||= {}
266
266
  find_selections(subselections_by_type, subselections_on_type, on_type, frag_defn.selections, arguments)
267
267
  else
@@ -35,7 +35,7 @@ module GraphQL
35
35
  @queries = queries
36
36
  @queries.each { |q| q.multiplex = self }
37
37
  @context = context
38
- @context[:dataloader] = @dataloader = @schema.dataloader_class.new
38
+ @dataloader = @context[:dataloader] ||= @schema.dataloader_class.new
39
39
  @tracers = schema.tracers + (context[:tracers] || [])
40
40
  # Support `context: {backtrace: true}`
41
41
  if context[:backtrace] && !@tracers.include?(GraphQL::Backtrace::Tracer)
@@ -10,7 +10,7 @@ module GraphQL
10
10
  "skipping a field. Directives provide this by describing additional information "\
11
11
  "to the executor."
12
12
  field :name, String, null: false, method: :graphql_name
13
- field :description, String, null: true
13
+ field :description, String
14
14
  field :locations, [GraphQL::Schema::LateBoundType.new("__DirectiveLocation")], null: false
15
15
  field :args, [GraphQL::Schema::LateBoundType.new("__InputValue")], null: false do
16
16
  argument :include_deprecated, Boolean, required: false, default_value: false
@@ -3,8 +3,8 @@ module GraphQL
3
3
  module Introspection
4
4
  class EntryPoints < Introspection::BaseObject
5
5
  field :__schema, GraphQL::Schema::LateBoundType.new("__Schema"), "This GraphQL schema", null: false
6
- field :__type, GraphQL::Schema::LateBoundType.new("__Type"), "A type in the GraphQL system", null: true do
7
- argument :name, String, required: true
6
+ field :__type, GraphQL::Schema::LateBoundType.new("__Type"), "A type in the GraphQL system" do
7
+ argument :name, String
8
8
  end
9
9
 
10
10
  def __schema
@@ -7,9 +7,9 @@ module GraphQL
7
7
  "placeholder for a string or numeric value. However an Enum value is returned in "\
8
8
  "a JSON response as a string."
9
9
  field :name, String, null: false
10
- field :description, String, null: true
10
+ field :description, String
11
11
  field :is_deprecated, Boolean, null: false
12
- field :deprecation_reason, String, null: true
12
+ field :deprecation_reason, String
13
13
 
14
14
  def name
15
15
  object.graphql_name
@@ -6,13 +6,13 @@ module GraphQL
6
6
  description "Object and Interface types are described by a list of Fields, each of which has "\
7
7
  "a name, potentially a list of arguments, and a return type."
8
8
  field :name, String, null: false
9
- field :description, String, null: true
9
+ field :description, String
10
10
  field :args, [GraphQL::Schema::LateBoundType.new("__InputValue")], null: false do
11
11
  argument :include_deprecated, Boolean, required: false, default_value: false
12
12
  end
13
13
  field :type, GraphQL::Schema::LateBoundType.new("__Type"), null: false
14
14
  field :is_deprecated, Boolean, null: false
15
- field :deprecation_reason, String, null: true
15
+ field :deprecation_reason, String
16
16
 
17
17
  def is_deprecated
18
18
  !!@object.deprecation_reason
@@ -7,11 +7,11 @@ module GraphQL
7
7
  "InputObject are represented as Input Values which describe their type and "\
8
8
  "optionally a default value."
9
9
  field :name, String, null: false
10
- field :description, String, null: true
10
+ field :description, String
11
11
  field :type, GraphQL::Schema::LateBoundType.new("__Type"), null: false
12
- field :default_value, String, "A GraphQL-formatted string representing the default value for this input value.", null: true
12
+ field :default_value, String, "A GraphQL-formatted string representing the default value for this input value."
13
13
  field :is_deprecated, Boolean, null: false
14
- field :deprecation_reason, String, null: true
14
+ field :deprecation_reason, String
15
15
 
16
16
  def is_deprecated
17
17
  !!@object.deprecation_reason
@@ -54,7 +54,7 @@ module GraphQL
54
54
  elsif type.kind.input_object?
55
55
  "{" +
56
56
  value.map do |k, v|
57
- arg_defn = type.arguments[k]
57
+ arg_defn = type.get_argument(k, context)
58
58
  "#{k}: #{serialize_default_value(v, arg_defn.type)}"
59
59
  end.join(", ") +
60
60
  "}"
@@ -10,8 +10,8 @@ module GraphQL
10
10
 
11
11
  field :types, [GraphQL::Schema::LateBoundType.new("__Type")], "A list of all types supported by this server.", null: false
12
12
  field :query_type, GraphQL::Schema::LateBoundType.new("__Type"), "The type that query operations will be rooted at.", null: false
13
- field :mutation_type, GraphQL::Schema::LateBoundType.new("__Type"), "If this server supports mutation, the type that mutation operations will be rooted at.", null: true
14
- field :subscription_type, GraphQL::Schema::LateBoundType.new("__Type"), "If this server support subscription, the type that subscription operations will be rooted at.", null: true
13
+ field :mutation_type, GraphQL::Schema::LateBoundType.new("__Type"), "If this server supports mutation, the type that mutation operations will be rooted at."
14
+ field :subscription_type, GraphQL::Schema::LateBoundType.new("__Type"), "If this server support subscription, the type that subscription operations will be rooted at."
15
15
  field :directives, [GraphQL::Schema::LateBoundType.new("__Directive")], "A list of all directives supported by this server.", null: false
16
16
 
17
17
  def types
@@ -12,20 +12,20 @@ module GraphQL
12
12
  "possible at runtime. List and NonNull types compose other types."
13
13
 
14
14
  field :kind, GraphQL::Schema::LateBoundType.new("__TypeKind"), null: false
15
- field :name, String, null: true
16
- field :description, String, null: true
17
- field :fields, [GraphQL::Schema::LateBoundType.new("__Field")], null: true do
15
+ field :name, String
16
+ field :description, String
17
+ field :fields, [GraphQL::Schema::LateBoundType.new("__Field")] do
18
18
  argument :include_deprecated, Boolean, required: false, default_value: false
19
19
  end
20
- field :interfaces, [GraphQL::Schema::LateBoundType.new("__Type")], null: true
21
- field :possible_types, [GraphQL::Schema::LateBoundType.new("__Type")], null: true
22
- field :enum_values, [GraphQL::Schema::LateBoundType.new("__EnumValue")], null: true do
20
+ field :interfaces, [GraphQL::Schema::LateBoundType.new("__Type")]
21
+ field :possible_types, [GraphQL::Schema::LateBoundType.new("__Type")]
22
+ field :enum_values, [GraphQL::Schema::LateBoundType.new("__EnumValue")] do
23
23
  argument :include_deprecated, Boolean, required: false, default_value: false
24
24
  end
25
- field :input_fields, [GraphQL::Schema::LateBoundType.new("__InputValue")], null: true do
25
+ field :input_fields, [GraphQL::Schema::LateBoundType.new("__InputValue")] do
26
26
  argument :include_deprecated, Boolean, required: false, default_value: false
27
27
  end
28
- field :of_type, GraphQL::Schema::LateBoundType.new("__Type"), null: true
28
+ field :of_type, GraphQL::Schema::LateBoundType.new("__Type")
29
29
 
30
30
  def name
31
31
  object.graphql_name
@@ -50,8 +50,8 @@ module GraphQL
50
50
  end
51
51
 
52
52
  def interfaces
53
- if @object.kind == GraphQL::TypeKinds::OBJECT
54
- @context.warden.interfaces(@object)
53
+ if @object.kind.object? || @object.kind.interface?
54
+ @context.warden.interfaces(@object).sort_by(&:graphql_name)
55
55
  else
56
56
  nil
57
57
  end
@@ -2,10 +2,6 @@
2
2
  module GraphQL
3
3
  module Language
4
4
  module BlockString
5
- if !String.method_defined?(:match?)
6
- using GraphQL::StringMatchBackport
7
- end
8
-
9
5
  # Remove leading and trailing whitespace from a block string.
10
6
  # See "Block Strings" in https://github.com/facebook/graphql/blob/master/spec/Section%202%20--%20Language.md
11
7
  def self.trim_whitespace(str)
@@ -34,6 +34,7 @@ module GraphQL
34
34
  schema: @schema,
35
35
  context: schema_context,
36
36
  )
37
+ schema_context.warden = @warden
37
38
  end
38
39
 
39
40
  def document
@@ -87,6 +88,7 @@ module GraphQL
87
88
  def build_interface_type_node(interface_type)
88
89
  GraphQL::Language::Nodes::InterfaceTypeDefinition.new(
89
90
  name: interface_type.graphql_name,
91
+ interfaces: warden.interfaces(interface_type).sort_by(&:graphql_name).map { |type| build_type_name_node(type) },
90
92
  description: interface_type.description,
91
93
  fields: build_field_nodes(warden.fields(interface_type)),
92
94
  directives: directives(interface_type),
@@ -194,7 +196,7 @@ module GraphQL
194
196
  when "INPUT_OBJECT"
195
197
  GraphQL::Language::Nodes::InputObject.new(
196
198
  arguments: default_value.to_h.map do |arg_name, arg_value|
197
- arg_type = type.arguments.fetch(arg_name.to_s).type
199
+ arg_type = @warden.arguments(type).find { |a| a.graphql_name == arg_name.to_s }.type
198
200
  GraphQL::Language::Nodes::Argument.new(
199
201
  name: arg_name.to_s,
200
202
  value: build_default_value(arg_value, arg_type)
@@ -295,7 +297,7 @@ module GraphQL
295
297
  else
296
298
  member.directives.map do |dir|
297
299
  args = []
298
- dir.arguments.argument_values.each_value do |arg_value|
300
+ dir.arguments.argument_values.each_value do |arg_value| # rubocop:disable Development/ContextIsPassedCop -- directive instance method
299
301
  arg_defn = arg_value.definition
300
302
  if arg_defn.default_value? && arg_value.value == arg_defn.default_value
301
303
  next