graphql 1.12.25 → 1.13.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.

Potentially problematic release.


This version of graphql might be problematic. Click here for more details.

Files changed (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 +4 -8
  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 +3 -14
  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 +11 -9
  49. data/lib/graphql/schema/build_from_definition.rb +12 -13
  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 -6
  56. data/lib/graphql/schema/enum.rb +57 -9
  57. data/lib/graphql/schema/enum_value.rb +5 -1
  58. data/lib/graphql/schema/field/connection_extension.rb +1 -1
  59. data/lib/graphql/schema/field.rb +92 -18
  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 +11 -13
  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 +8 -15
  89. data/lib/graphql/static_validation/rules/required_arguments_are_present.rb +1 -3
  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 +14 -6
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 582e38c72afb32d38c7a256d1eb811a7ef0e13b8984c10370e278f038c639343
4
- data.tar.gz: 2fc62afb65909e4e08d5ad42c2c5c40a48a7acedca8afa5ac512a4aa60284a8e
3
+ metadata.gz: 853fa0482ef0c3bafe04dce77dff9bb685633a1e4c273fd234169f98d595352c
4
+ data.tar.gz: 6cf800af8dfc469f4d7a375ee22f6d98e03207799f813f10176916f09a0a4064
5
5
  SHA512:
6
- metadata.gz: 922e24767106339ff4e441cc9597a6a974814371180aa5bdaab2db7608ac590610199af451f0dfc85019dd4a531bb7934e57a60f7cf976be1c095f3722866474
7
- data.tar.gz: dd2b9fb0f9f26dd8ad3b3841516eadd66b05765de3f0490eafce49fc29599cc6894f1a0d376b3f3bef47d850fd3948ff7b03256721575a2ae6b06f6fd6741736
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
 
@@ -15,12 +15,8 @@ module GraphQL
15
15
  field = "#{visitor.parent_type_definition.graphql_name}.#{field_defn.graphql_name}"
16
16
  @used_fields << field
17
17
  @used_deprecated_fields << field if field_defn.deprecation_reason
18
- arguments = visitor.query.arguments_for(node, visitor.field_definition)
19
- # If there was an error when preparing this argument object,
20
- # then this might be an error or something:
21
- if arguments.respond_to?(:argument_values)
22
- extract_deprecated_arguments(arguments.argument_values)
23
- end
18
+
19
+ extract_deprecated_arguments(visitor.query.arguments_for(node, visitor.field_definition).argument_values)
24
20
  end
25
21
 
26
22
  def result
@@ -40,12 +36,12 @@ module GraphQL
40
36
  end
41
37
 
42
38
  if argument.definition.type.kind.input_object?
43
- extract_deprecated_arguments(argument.value.arguments.argument_values)
39
+ extract_deprecated_arguments(argument.value.arguments.argument_values) # rubocop:disable Development/ContextIsPassedCop -- runtime args instance
44
40
  elsif argument.definition.type.list? && !argument.value.nil?
45
41
  argument
46
42
  .value
47
43
  .select { |value| value.respond_to?(:arguments) }
48
- .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
49
45
  end
50
46
  end
51
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)