graphql 1.12.23 → 1.13.3

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 (134) hide show
  1. checksums.yaml +4 -4
  2. data/lib/generators/graphql/core.rb +3 -1
  3. data/lib/generators/graphql/install_generator.rb +9 -2
  4. data/lib/generators/graphql/mutation_generator.rb +1 -1
  5. data/lib/generators/graphql/type_generator.rb +0 -1
  6. data/lib/graphql/analysis/ast/field_usage.rb +2 -2
  7. data/lib/graphql/analysis/ast/query_complexity.rb +10 -14
  8. data/lib/graphql/analysis/ast/visitor.rb +4 -4
  9. data/lib/graphql/backtrace/table.rb +1 -1
  10. data/lib/graphql/base_type.rb +4 -2
  11. data/lib/graphql/boolean_type.rb +1 -1
  12. data/lib/graphql/dataloader.rb +55 -22
  13. data/lib/graphql/directive/deprecated_directive.rb +1 -1
  14. data/lib/graphql/directive/include_directive.rb +1 -1
  15. data/lib/graphql/directive/skip_directive.rb +1 -1
  16. data/lib/graphql/directive.rb +0 -4
  17. data/lib/graphql/enum_type.rb +5 -1
  18. data/lib/graphql/execution/errors.rb +1 -0
  19. data/lib/graphql/execution/interpreter/arguments.rb +1 -1
  20. data/lib/graphql/execution/interpreter/arguments_cache.rb +2 -2
  21. data/lib/graphql/execution/interpreter/runtime.rb +31 -19
  22. data/lib/graphql/execution/lookahead.rb +2 -2
  23. data/lib/graphql/execution/multiplex.rb +4 -1
  24. data/lib/graphql/float_type.rb +1 -1
  25. data/lib/graphql/id_type.rb +1 -1
  26. data/lib/graphql/int_type.rb +1 -1
  27. data/lib/graphql/introspection/directive_type.rb +1 -1
  28. data/lib/graphql/introspection/entry_points.rb +2 -2
  29. data/lib/graphql/introspection/enum_value_type.rb +2 -2
  30. data/lib/graphql/introspection/field_type.rb +2 -2
  31. data/lib/graphql/introspection/input_value_type.rb +4 -4
  32. data/lib/graphql/introspection/schema_type.rb +2 -2
  33. data/lib/graphql/introspection/type_type.rb +10 -10
  34. data/lib/graphql/language/block_string.rb +2 -6
  35. data/lib/graphql/language/document_from_schema_definition.rb +10 -4
  36. data/lib/graphql/language/lexer.rb +0 -3
  37. data/lib/graphql/language/lexer.rl +0 -4
  38. data/lib/graphql/language/nodes.rb +3 -2
  39. data/lib/graphql/language/parser.rb +442 -434
  40. data/lib/graphql/language/parser.y +5 -4
  41. data/lib/graphql/language/printer.rb +6 -1
  42. data/lib/graphql/language/sanitized_printer.rb +5 -5
  43. data/lib/graphql/language/token.rb +0 -4
  44. data/lib/graphql/name_validator.rb +0 -4
  45. data/lib/graphql/pagination/active_record_relation_connection.rb +43 -6
  46. data/lib/graphql/pagination/relation_connection.rb +55 -28
  47. data/lib/graphql/query/arguments.rb +1 -1
  48. data/lib/graphql/query/arguments_cache.rb +1 -1
  49. data/lib/graphql/query/context.rb +15 -2
  50. data/lib/graphql/query/literal_input.rb +1 -1
  51. data/lib/graphql/query/null_context.rb +12 -7
  52. data/lib/graphql/query/serial_execution/field_resolution.rb +1 -1
  53. data/lib/graphql/query/variables.rb +5 -1
  54. data/lib/graphql/relay/edges_instrumentation.rb +0 -1
  55. data/lib/graphql/relay/global_id_resolve.rb +1 -1
  56. data/lib/graphql/relay/page_info.rb +1 -1
  57. data/lib/graphql/rubocop/graphql/base_cop.rb +36 -0
  58. data/lib/graphql/rubocop/graphql/default_null_true.rb +43 -0
  59. data/lib/graphql/rubocop/graphql/default_required_true.rb +43 -0
  60. data/lib/graphql/rubocop.rb +4 -0
  61. data/lib/graphql/schema/addition.rb +37 -28
  62. data/lib/graphql/schema/argument.rb +13 -15
  63. data/lib/graphql/schema/build_from_definition.rb +5 -5
  64. data/lib/graphql/schema/directive/feature.rb +1 -1
  65. data/lib/graphql/schema/directive/flagged.rb +2 -2
  66. data/lib/graphql/schema/directive/include.rb +1 -1
  67. data/lib/graphql/schema/directive/skip.rb +1 -1
  68. data/lib/graphql/schema/directive/transform.rb +1 -1
  69. data/lib/graphql/schema/directive.rb +7 -3
  70. data/lib/graphql/schema/enum.rb +60 -10
  71. data/lib/graphql/schema/enum_value.rb +6 -0
  72. data/lib/graphql/schema/field/connection_extension.rb +1 -1
  73. data/lib/graphql/schema/field.rb +229 -77
  74. data/lib/graphql/schema/field_extension.rb +89 -2
  75. data/lib/graphql/schema/find_inherited_value.rb +1 -0
  76. data/lib/graphql/schema/finder.rb +5 -5
  77. data/lib/graphql/schema/input_object.rb +23 -5
  78. data/lib/graphql/schema/interface.rb +11 -20
  79. data/lib/graphql/schema/introspection_system.rb +1 -1
  80. data/lib/graphql/schema/list.rb +3 -1
  81. data/lib/graphql/schema/member/accepts_definition.rb +15 -3
  82. data/lib/graphql/schema/member/build_type.rb +0 -4
  83. data/lib/graphql/schema/member/cached_graphql_definition.rb +29 -2
  84. data/lib/graphql/schema/member/has_arguments.rb +55 -13
  85. data/lib/graphql/schema/member/has_deprecation_reason.rb +1 -1
  86. data/lib/graphql/schema/member/has_fields.rb +76 -18
  87. data/lib/graphql/schema/member/has_interfaces.rb +90 -0
  88. data/lib/graphql/schema/member.rb +1 -0
  89. data/lib/graphql/schema/non_null.rb +7 -1
  90. data/lib/graphql/schema/object.rb +10 -75
  91. data/lib/graphql/schema/printer.rb +1 -1
  92. data/lib/graphql/schema/relay_classic_mutation.rb +37 -3
  93. data/lib/graphql/schema/resolver/has_payload_type.rb +27 -2
  94. data/lib/graphql/schema/resolver.rb +37 -17
  95. data/lib/graphql/schema/scalar.rb +2 -0
  96. data/lib/graphql/schema/subscription.rb +11 -1
  97. data/lib/graphql/schema/traversal.rb +1 -1
  98. data/lib/graphql/schema/type_expression.rb +1 -1
  99. data/lib/graphql/schema/type_membership.rb +18 -4
  100. data/lib/graphql/schema/union.rb +8 -1
  101. data/lib/graphql/schema/validator/format_validator.rb +0 -4
  102. data/lib/graphql/schema/validator/numericality_validator.rb +1 -0
  103. data/lib/graphql/schema/validator/required_validator.rb +29 -15
  104. data/lib/graphql/schema/validator.rb +4 -7
  105. data/lib/graphql/schema/warden.rb +116 -52
  106. data/lib/graphql/schema.rb +111 -23
  107. data/lib/graphql/static_validation/all_rules.rb +1 -0
  108. data/lib/graphql/static_validation/base_visitor.rb +5 -5
  109. data/lib/graphql/static_validation/definition_dependencies.rb +0 -1
  110. data/lib/graphql/static_validation/literal_validator.rb +1 -1
  111. data/lib/graphql/static_validation/rules/argument_literals_are_compatible.rb +1 -1
  112. data/lib/graphql/static_validation/rules/fields_will_merge.rb +1 -1
  113. data/lib/graphql/static_validation/rules/query_root_exists.rb +17 -0
  114. data/lib/graphql/static_validation/rules/query_root_exists_error.rb +26 -0
  115. data/lib/graphql/static_validation/rules/required_arguments_are_present.rb +2 -2
  116. data/lib/graphql/static_validation/rules/required_input_object_attributes_are_present.rb +4 -4
  117. data/lib/graphql/static_validation/rules/variable_usages_are_allowed.rb +13 -7
  118. data/lib/graphql/string_type.rb +1 -1
  119. data/lib/graphql/subscriptions/action_cable_subscriptions.rb +8 -4
  120. data/lib/graphql/subscriptions/event.rb +20 -12
  121. data/lib/graphql/subscriptions/serialize.rb +22 -2
  122. data/lib/graphql/subscriptions.rb +17 -19
  123. data/lib/graphql/tracing/active_support_notifications_tracing.rb +6 -20
  124. data/lib/graphql/tracing/notifications_tracing.rb +59 -0
  125. data/lib/graphql/types/relay/connection_behaviors.rb +26 -9
  126. data/lib/graphql/types/relay/default_relay.rb +5 -1
  127. data/lib/graphql/types/relay/edge_behaviors.rb +13 -2
  128. data/lib/graphql/types/relay/has_node_field.rb +1 -1
  129. data/lib/graphql/types/relay/has_nodes_field.rb +1 -1
  130. data/lib/graphql/types/relay/node_field.rb +14 -3
  131. data/lib/graphql/types/relay/nodes_field.rb +13 -3
  132. data/lib/graphql/version.rb +1 -1
  133. data/lib/graphql.rb +10 -32
  134. metadata +13 -5
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 9e95b4e227ec93bce92db8d50253b83fdd8f310e7a41fca40db6df9e95b6d96a
4
- data.tar.gz: b97ac815e644d1c2e7b8b8ea43c28f9a9247ad8d9cec5e90145ffc98ad2987a8
3
+ metadata.gz: b2638039468d2557513228b7bda7e148a91c02b818090fee27ddc92c9c3ea88a
4
+ data.tar.gz: 7ae7b8ba26ec64075dd226e3be092cd1216c4b137ce8935e8972e66df3c09c35
5
5
  SHA512:
6
- metadata.gz: 64dc815853f24b6c6be56e24ed2058696f4e37479d48aba44b6da7d280c80e6d44af07d9002295b4d1f2d1082ec07a3513a2d5440d7682178ebb46fdaad01c84
7
- data.tar.gz: 65672dab093d67208b1826000f9c3a7bc8125b085c72b8056820894a2c9f7d79ac4f3fd4b2aa519e944bbeb741bf9060b1c730f32a20ef1d1278c7b70ec56ece
6
+ metadata.gz: 54c9be19ab4e29e59af43c251fc661b4d9ae47208eab4461361aef3f460f54422cef1215f4311bb6e10d18571629ea176b46aae78b9bdb9181670dcd72a0fa1d
7
+ data.tar.gz: b2c3ec10e2600b39d555946d9ba88092eba38f8dd9b7cfd3836ab5341ec59878a1df3d1d295d9889692ed32c9e6e07e1bf307928f8f3d8a199380709070ced4c
@@ -19,7 +19,9 @@ module Graphql
19
19
  sentinel = /< GraphQL::Schema\s*\n/m
20
20
 
21
21
  in_root do
22
- inject_into_file schema_file_path, " #{type}(Types::#{name})\n", after: sentinel, verbose: false, force: false
22
+ if File.exist?(schema_file_path)
23
+ inject_into_file schema_file_path, " #{type}(Types::#{name})\n", after: sentinel, verbose: false, force: false
24
+ end
23
25
  end
24
26
  end
25
27
 
@@ -122,8 +122,15 @@ module Graphql
122
122
  if options.api?
123
123
  say("Skipped graphiql, as this rails project is API only")
124
124
  say(" You may wish to use GraphiQL.app for development: https://github.com/skevy/graphiql-app")
125
- elsif !options[:skip_graphiql] && !File.read(Rails.root.join("Gemfile")).include?("graphiql-rails")
126
- gem("graphiql-rails", group: :development)
125
+ elsif !options[:skip_graphiql]
126
+ # `gem(...)` uses `gsub_file(...)` under the hood, which is a no-op for `rails destroy...` (when `behavior == :revoke`).
127
+ # So handle that case by calling `gsub_file` with `force: true`.
128
+ if behavior == :invoke && !File.read(Rails.root.join("Gemfile")).include?("graphiql-rails")
129
+ gem("graphiql-rails", group: :development)
130
+ elsif behavior == :revoke
131
+ gemfile_pattern = /\n\s*gem ('|")graphiql-rails('|"), :?group(:| =>) :development/
132
+ gsub_file Rails.root.join("Gemfile"), gemfile_pattern, "", { force: true }
133
+ end
127
134
 
128
135
  # This is a little cheat just to get cleaner shell output:
129
136
  log :route, 'graphiql-rails'
@@ -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
 
@@ -40,12 +40,12 @@ module GraphQL
40
40
  end
41
41
 
42
42
  if argument.definition.type.kind.input_object?
43
- extract_deprecated_arguments(argument.value.arguments.argument_values)
43
+ extract_deprecated_arguments(argument.value.arguments.argument_values) # rubocop:disable Development/ContextIsPassedCop -- runtime args instance
44
44
  elsif argument.definition.type.list? && !argument.value.nil?
45
45
  argument
46
46
  .value
47
47
  .select { |value| value.respond_to?(:arguments) }
48
- .each { |value| extract_deprecated_arguments(value.arguments.argument_values) }
48
+ .each { |value| extract_deprecated_arguments(value.arguments.argument_values) } # rubocop:disable Development/ContextIsPassedCop -- runtime args instance
49
49
  end
50
50
  end
51
51
  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)
@@ -41,7 +41,9 @@ module GraphQL
41
41
  alias :graphql_name :name
42
42
  # Future-compatible alias
43
43
  # @see {GraphQL::SchemaMember}
44
- alias :graphql_definition :itself
44
+ def graphql_definition(silence_deprecation_warning: false)
45
+ itself
46
+ end
45
47
 
46
48
  def type_class
47
49
  metadata[:type_class]
@@ -194,7 +196,7 @@ module GraphQL
194
196
  resolve_related_type(Object.const_get(type_arg))
195
197
  else
196
198
  if type_arg.respond_to?(:graphql_definition)
197
- type_arg.graphql_definition
199
+ type_arg.graphql_definition(silence_deprecation_warning: true)
198
200
  else
199
201
  type_arg
200
202
  end
@@ -1,2 +1,2 @@
1
1
  # frozen_string_literal: true
2
- GraphQL::BOOLEAN_TYPE = GraphQL::Types::Boolean.graphql_definition
2
+ GraphQL::BOOLEAN_TYPE = GraphQL::Types::Boolean.graphql_definition(silence_deprecation_warning: true)
@@ -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
@@ -1,2 +1,2 @@
1
1
  # frozen_string_literal: true
2
- GraphQL::Directive::DeprecatedDirective = GraphQL::Schema::Directive::Deprecated.graphql_definition
2
+ GraphQL::Directive::DeprecatedDirective = GraphQL::Schema::Directive::Deprecated.graphql_definition(silence_deprecation_warning: true)
@@ -1,2 +1,2 @@
1
1
  # frozen_string_literal: true
2
- GraphQL::Directive::IncludeDirective = GraphQL::Schema::Directive::Include.graphql_definition
2
+ GraphQL::Directive::IncludeDirective = GraphQL::Schema::Directive::Include.graphql_definition(silence_deprecation_warning: true)
@@ -1,2 +1,2 @@
1
1
  # frozen_string_literal: true
2
- GraphQL::Directive::SkipDirective = GraphQL::Schema::Directive::Skip.graphql_definition
2
+ GraphQL::Directive::SkipDirective = GraphQL::Schema::Directive::Skip.graphql_definition(silence_deprecation_warning: true)
@@ -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,10 +513,10 @@ 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
- continue_field(next_path, continue_value, owner_type, field_defn, return_type, ast_node, next_selections, false, object, kwarg_arguments, result_name, selection_result)
519
+ continue_field(next_path, continue_value, owner_type, field_defn, return_type, ast_node, next_selections, false, object, resolved_arguments, result_name, selection_result)
518
520
  end
519
521
  end
520
522
  end
@@ -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
@@ -862,16 +870,20 @@ module GraphQL
862
870
  # but don't wrap the continuation below
863
871
  inner_obj = begin
864
872
  query.with_error_handling do
865
- if trace
866
- query.trace("execute_field_lazy", {owner: owner, field: field, path: path, query: query, object: owner_object, arguments: arguments, ast_node: ast_node}) do
873
+ begin
874
+ if trace
875
+ query.trace("execute_field_lazy", {owner: owner, field: field, path: path, query: query, object: owner_object, arguments: arguments, ast_node: ast_node}) do
876
+ schema.sync_lazy(lazy_obj)
877
+ end
878
+ else
867
879
  schema.sync_lazy(lazy_obj)
868
880
  end
869
- else
870
- schema.sync_lazy(lazy_obj)
881
+ rescue GraphQL::ExecutionError, GraphQL::UnauthorizedError => err
882
+ err
871
883
  end
872
884
  end
873
- rescue GraphQL::ExecutionError, GraphQL::UnauthorizedError => err
874
- err
885
+ rescue GraphQL::ExecutionError => ex_err
886
+ ex_err
875
887
  end
876
888
  yield(inner_obj)
877
889
  end
@@ -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)
@@ -151,6 +151,9 @@ module GraphQL
151
151
 
152
152
  result
153
153
  end
154
+ if query.context.namespace?(:__query_result_extensions__)
155
+ query.result_values["extensions"] = query.context.namespace(:__query_result_extensions__)
156
+ end
154
157
  end
155
158
 
156
159
  # use the old `query_execution_strategy` etc to run this query
@@ -1,2 +1,2 @@
1
1
  # frozen_string_literal: true
2
- GraphQL::FLOAT_TYPE = GraphQL::Types::Float.graphql_definition
2
+ GraphQL::FLOAT_TYPE = GraphQL::Types::Float.graphql_definition(silence_deprecation_warning: true)
@@ -1,2 +1,2 @@
1
1
  # frozen_string_literal: true
2
- GraphQL::ID_TYPE = GraphQL::Types::ID.graphql_definition
2
+ GraphQL::ID_TYPE = GraphQL::Types::ID.graphql_definition(silence_deprecation_warning: true)
@@ -1,2 +1,2 @@
1
1
  # frozen_string_literal: true
2
- GraphQL::INT_TYPE = GraphQL::Types::Int.graphql_definition
2
+ GraphQL::INT_TYPE = GraphQL::Types::Int.graphql_definition(silence_deprecation_warning: true)
@@ -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