graphql 1.11.1 → 1.11.6

Sign up to get free protection for your applications and to get access to all the features.
Files changed (94) hide show
  1. checksums.yaml +4 -4
  2. data/lib/generators/graphql/core.rb +8 -0
  3. data/lib/generators/graphql/templates/base_argument.erb +2 -0
  4. data/lib/generators/graphql/templates/base_enum.erb +2 -0
  5. data/lib/generators/graphql/templates/base_field.erb +2 -0
  6. data/lib/generators/graphql/templates/base_input_object.erb +2 -0
  7. data/lib/generators/graphql/templates/base_interface.erb +2 -0
  8. data/lib/generators/graphql/templates/base_mutation.erb +2 -0
  9. data/lib/generators/graphql/templates/base_object.erb +2 -0
  10. data/lib/generators/graphql/templates/base_scalar.erb +2 -0
  11. data/lib/generators/graphql/templates/base_union.erb +2 -0
  12. data/lib/generators/graphql/templates/enum.erb +2 -0
  13. data/lib/generators/graphql/templates/graphql_controller.erb +13 -9
  14. data/lib/generators/graphql/templates/interface.erb +2 -0
  15. data/lib/generators/graphql/templates/loader.erb +2 -0
  16. data/lib/generators/graphql/templates/mutation.erb +2 -0
  17. data/lib/generators/graphql/templates/mutation_type.erb +2 -0
  18. data/lib/generators/graphql/templates/object.erb +2 -0
  19. data/lib/generators/graphql/templates/query_type.erb +2 -0
  20. data/lib/generators/graphql/templates/scalar.erb +2 -0
  21. data/lib/generators/graphql/templates/schema.erb +2 -0
  22. data/lib/generators/graphql/templates/union.erb +3 -1
  23. data/lib/graphql.rb +16 -0
  24. data/lib/graphql/argument.rb +3 -3
  25. data/lib/graphql/backtrace/tracer.rb +2 -1
  26. data/lib/graphql/define/assign_global_id_field.rb +2 -2
  27. data/lib/graphql/directive.rb +4 -0
  28. data/lib/graphql/execution/interpreter.rb +10 -0
  29. data/lib/graphql/execution/interpreter/arguments.rb +1 -1
  30. data/lib/graphql/execution/interpreter/runtime.rb +59 -45
  31. data/lib/graphql/field.rb +4 -0
  32. data/lib/graphql/input_object_type.rb +4 -0
  33. data/lib/graphql/introspection.rb +96 -0
  34. data/lib/graphql/introspection/field_type.rb +7 -3
  35. data/lib/graphql/introspection/input_value_type.rb +6 -0
  36. data/lib/graphql/introspection/introspection_query.rb +6 -92
  37. data/lib/graphql/introspection/type_type.rb +7 -3
  38. data/lib/graphql/language/block_string.rb +24 -5
  39. data/lib/graphql/language/lexer.rb +7 -3
  40. data/lib/graphql/language/lexer.rl +7 -3
  41. data/lib/graphql/language/nodes.rb +2 -1
  42. data/lib/graphql/language/parser.rb +107 -103
  43. data/lib/graphql/language/parser.y +4 -0
  44. data/lib/graphql/language/sanitized_printer.rb +59 -26
  45. data/lib/graphql/language/visitor.rb +2 -2
  46. data/lib/graphql/name_validator.rb +6 -7
  47. data/lib/graphql/pagination/connection.rb +6 -8
  48. data/lib/graphql/pagination/connections.rb +23 -3
  49. data/lib/graphql/query.rb +2 -2
  50. data/lib/graphql/query/context.rb +30 -3
  51. data/lib/graphql/query/fingerprint.rb +2 -0
  52. data/lib/graphql/query/validation_pipeline.rb +3 -0
  53. data/lib/graphql/relay/range_add.rb +14 -5
  54. data/lib/graphql/schema.rb +40 -31
  55. data/lib/graphql/schema/argument.rb +56 -5
  56. data/lib/graphql/schema/build_from_definition.rb +67 -38
  57. data/lib/graphql/schema/build_from_definition/resolve_map.rb +3 -1
  58. data/lib/graphql/schema/directive/deprecated.rb +1 -1
  59. data/lib/graphql/schema/enum_value.rb +1 -0
  60. data/lib/graphql/schema/field.rb +17 -10
  61. data/lib/graphql/schema/field/connection_extension.rb +44 -34
  62. data/lib/graphql/schema/input_object.rb +21 -18
  63. data/lib/graphql/schema/interface.rb +1 -1
  64. data/lib/graphql/schema/late_bound_type.rb +2 -2
  65. data/lib/graphql/schema/loader.rb +20 -1
  66. data/lib/graphql/schema/member/build_type.rb +14 -4
  67. data/lib/graphql/schema/member/has_arguments.rb +19 -1
  68. data/lib/graphql/schema/member/has_fields.rb +17 -7
  69. data/lib/graphql/schema/member/type_system_helpers.rb +2 -2
  70. data/lib/graphql/schema/mutation.rb +4 -0
  71. data/lib/graphql/schema/relay_classic_mutation.rb +3 -1
  72. data/lib/graphql/schema/resolver.rb +6 -0
  73. data/lib/graphql/schema/resolver/has_payload_type.rb +2 -1
  74. data/lib/graphql/schema/subscription.rb +2 -12
  75. data/lib/graphql/schema/timeout.rb +29 -15
  76. data/lib/graphql/schema/union.rb +29 -0
  77. data/lib/graphql/schema/unique_within_type.rb +1 -2
  78. data/lib/graphql/schema/validation.rb +8 -0
  79. data/lib/graphql/schema/warden.rb +8 -3
  80. data/lib/graphql/static_validation/literal_validator.rb +7 -7
  81. data/lib/graphql/static_validation/rules/arguments_are_defined.rb +1 -1
  82. data/lib/graphql/static_validation/rules/required_arguments_are_present.rb +2 -2
  83. data/lib/graphql/static_validation/rules/required_input_object_attributes_are_present.rb +1 -2
  84. data/lib/graphql/static_validation/rules/variables_are_used_and_defined.rb +4 -2
  85. data/lib/graphql/static_validation/validator.rb +7 -4
  86. data/lib/graphql/subscriptions.rb +32 -22
  87. data/lib/graphql/subscriptions/action_cable_subscriptions.rb +45 -20
  88. data/lib/graphql/subscriptions/serialize.rb +22 -4
  89. data/lib/graphql/tracing/appoptics_tracing.rb +10 -2
  90. data/lib/graphql/types/iso_8601_date_time.rb +2 -1
  91. data/lib/graphql/types/relay/base_connection.rb +6 -5
  92. data/lib/graphql/unauthorized_error.rb +1 -1
  93. data/lib/graphql/version.rb +1 -1
  94. metadata +3 -3
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 2b152fd76301d994c8a685bce0539e409739c6e1e303c611c34a6424b2d2e68e
4
- data.tar.gz: 84215fce3790161bebfa183e05b69abe6394396bec177ce69f98e5a53484d7b5
3
+ metadata.gz: 1b6e1d6fb5063c843becb61784cb776964a380af5a2fc5a98054d2554ddf4caa
4
+ data.tar.gz: c41027cdf69f8c07bed157075c70e95936f3d26922f0b1d38f7759352a35ab43
5
5
  SHA512:
6
- metadata.gz: 83d130c2cd4c76f9869d60e4a32f80e2a20a3ff5c614e6852686c1d06d2da8b454065b5c382099877c2449e77f938f8ef5e2dfd69e22bf5a505e04a3edb8db2d
7
- data.tar.gz: 06bf9038ca1f32d03fc4a0fc2ed6763420ff58d7c7b4aaad38a703b0eb090c3a35fb829c2a7e13420c1507ea8013e5d7084067c733de98b416698ea39ba46ba3
6
+ metadata.gz: 3dc4e13b30d51c32775785b9ed4a11940bc2cb541866877e6eef48bc621956700ddf057c597d2bc5a9fa09ca863e01ba84295e414e488e22ee03b94c28bc4003
7
+ data.tar.gz: 70f5ba8c04e13b83af431db1e8edea297a3c43acc6f6356668094349b577fe7de4e8cdb029aaf8ce70cc243664915ac7dac38612badd0acb720ce57464769cec
@@ -41,6 +41,14 @@ module Graphql
41
41
  end
42
42
  end
43
43
 
44
+ def module_namespacing_when_supported
45
+ if defined?(module_namespacing)
46
+ module_namespacing { yield }
47
+ else
48
+ yield
49
+ end
50
+ end
51
+
44
52
  private
45
53
 
46
54
  def schema_name
@@ -1,4 +1,6 @@
1
+ <% module_namespacing_when_supported do -%>
1
2
  module Types
2
3
  class BaseArgument < GraphQL::Schema::Argument
3
4
  end
4
5
  end
6
+ <% end -%>
@@ -1,4 +1,6 @@
1
+ <% module_namespacing_when_supported do -%>
1
2
  module Types
2
3
  class BaseEnum < GraphQL::Schema::Enum
3
4
  end
4
5
  end
6
+ <% end -%>
@@ -1,5 +1,7 @@
1
+ <% module_namespacing_when_supported do -%>
1
2
  module Types
2
3
  class BaseField < GraphQL::Schema::Field
3
4
  argument_class Types::BaseArgument
4
5
  end
5
6
  end
7
+ <% end -%>
@@ -1,5 +1,7 @@
1
+ <% module_namespacing_when_supported do -%>
1
2
  module Types
2
3
  class BaseInputObject < GraphQL::Schema::InputObject
3
4
  argument_class Types::BaseArgument
4
5
  end
5
6
  end
7
+ <% end -%>
@@ -1,3 +1,4 @@
1
+ <% module_namespacing_when_supported do -%>
1
2
  module Types
2
3
  module BaseInterface
3
4
  include GraphQL::Schema::Interface
@@ -5,3 +6,4 @@ module Types
5
6
  field_class Types::BaseField
6
7
  end
7
8
  end
9
+ <% end -%>
@@ -1,3 +1,4 @@
1
+ <% module_namespacing_when_supported do -%>
1
2
  module Mutations
2
3
  class BaseMutation < GraphQL::Schema::RelayClassicMutation
3
4
  argument_class Types::BaseArgument
@@ -6,3 +7,4 @@ module Mutations
6
7
  object_class Types::BaseObject
7
8
  end
8
9
  end
10
+ <% end -%>
@@ -1,5 +1,7 @@
1
+ <% module_namespacing_when_supported do -%>
1
2
  module Types
2
3
  class BaseObject < GraphQL::Schema::Object
3
4
  field_class Types::BaseField
4
5
  end
5
6
  end
7
+ <% end -%>
@@ -1,4 +1,6 @@
1
+ <% module_namespacing_when_supported do -%>
1
2
  module Types
2
3
  class BaseScalar < GraphQL::Schema::Scalar
3
4
  end
4
5
  end
6
+ <% end -%>
@@ -1,4 +1,6 @@
1
+ <% module_namespacing_when_supported do -%>
1
2
  module Types
2
3
  class BaseUnion < GraphQL::Schema::Union
3
4
  end
4
5
  end
6
+ <% end -%>
@@ -1,5 +1,7 @@
1
+ <% module_namespacing_when_supported do -%>
1
2
  module Types
2
3
  class <%= type_ruby_name.split('::')[-1] %> < Types::BaseEnum
3
4
  <% prepared_values.each do |v| %> value "<%= v[0] %>"<%= v.length > 1 ? ", value: #{v[1]}" : "" %>
4
5
  <% end %> end
5
6
  end
7
+ <% end -%>
@@ -1,3 +1,4 @@
1
+ <% module_namespacing_when_supported do -%>
1
2
  class GraphqlController < ApplicationController
2
3
  # If accessing from outside this domain, nullify the session
3
4
  # This allows for outside API access while preventing CSRF attacks,
@@ -5,7 +6,7 @@ class GraphqlController < ApplicationController
5
6
  # protect_from_forgery with: :null_session
6
7
 
7
8
  def execute
8
- variables = ensure_hash(params[:variables])
9
+ variables = prepare_variables(params[:variables])
9
10
  query = params[:query]
10
11
  operation_name = params[:operationName]
11
12
  context = {
@@ -21,21 +22,23 @@ class GraphqlController < ApplicationController
21
22
 
22
23
  private
23
24
 
24
- # Handle form data, JSON body, or a blank value
25
- def ensure_hash(ambiguous_param)
26
- case ambiguous_param
25
+ # Handle variables in form data, JSON body, or a blank value
26
+ def prepare_variables(variables_param)
27
+ case variables_param
27
28
  when String
28
- if ambiguous_param.present?
29
- ensure_hash(JSON.parse(ambiguous_param))
29
+ if variables_param.present?
30
+ JSON.parse(variables_param) || {}
30
31
  else
31
32
  {}
32
33
  end
33
- when Hash, ActionController::Parameters
34
- ambiguous_param
34
+ when Hash
35
+ variables_param
36
+ when ActionController::Parameters
37
+ variables_param.to_unsafe_hash # GraphQL-Ruby will validate name and type of incoming variables.
35
38
  when nil
36
39
  {}
37
40
  else
38
- raise ArgumentError, "Unexpected parameter: #{ambiguous_param}"
41
+ raise ArgumentError, "Unexpected parameter: #{variables_param}"
39
42
  end
40
43
  end
41
44
 
@@ -46,3 +49,4 @@ class GraphqlController < ApplicationController
46
49
  render json: { errors: [{ message: e.message, backtrace: e.backtrace }], data: {} }, status: 500
47
50
  end
48
51
  end
52
+ <% end -%>
@@ -1,6 +1,8 @@
1
+ <% module_namespacing_when_supported do -%>
1
2
  module Types
2
3
  module <%= type_ruby_name.split('::')[-1] %>
3
4
  include Types::BaseInterface
4
5
  <% normalized_fields.each do |f| %> <%= f.to_ruby %>
5
6
  <% end %> end
6
7
  end
8
+ <% end -%>
@@ -1,3 +1,4 @@
1
+ <% module_namespacing_when_supported do -%>
1
2
  module Loaders
2
3
  class <%= class_name %> < GraphQL::Batch::Loader
3
4
  # Define `initialize` to store grouping arguments, eg
@@ -15,3 +16,4 @@ module Loaders
15
16
  end
16
17
  end
17
18
  end
19
+ <% end -%>
@@ -1,3 +1,4 @@
1
+ <% module_namespacing_when_supported do -%>
1
2
  module Mutations
2
3
  class <%= mutation_name %> < BaseMutation
3
4
  # TODO: define return fields
@@ -12,3 +13,4 @@ module Mutations
12
13
  # end
13
14
  end
14
15
  end
16
+ <% end -%>
@@ -1,3 +1,4 @@
1
+ <% module_namespacing_when_supported do -%>
1
2
  module Types
2
3
  class MutationType < Types::BaseObject
3
4
  # TODO: remove me
@@ -8,3 +9,4 @@ module Types
8
9
  end
9
10
  end
10
11
  end
12
+ <% end -%>
@@ -1,6 +1,8 @@
1
+ <% module_namespacing_when_supported do -%>
1
2
  module Types
2
3
  class <%= type_ruby_name.split('::')[-1] %> < Types::BaseObject
3
4
  <% if options.node %> implements GraphQL::Relay::Node.interface
4
5
  <% end %><% normalized_fields.each do |f| %> <%= f.to_ruby %>
5
6
  <% end %> end
6
7
  end
8
+ <% end -%>
@@ -1,3 +1,4 @@
1
+ <% module_namespacing_when_supported do -%>
1
2
  module Types
2
3
  class QueryType < Types::BaseObject
3
4
  # Add root-level fields here.
@@ -13,3 +14,4 @@ module Types
13
14
  field :node, field: GraphQL::Relay::Node.field
14
15
  <% end %> end
15
16
  end
17
+ <% end -%>
@@ -1,3 +1,4 @@
1
+ <% module_namespacing_when_supported do -%>
1
2
  module Types
2
3
  class <%= type_ruby_name.split('::')[-1] %> < Types::BaseScalar
3
4
  def self.coerce_input(input_value, context)
@@ -11,3 +12,4 @@ module Types
11
12
  end
12
13
  end
13
14
  end
15
+ <% end -%>
@@ -1,3 +1,4 @@
1
+ <% module_namespacing_when_supported do -%>
1
2
  class <%= schema_name %> < GraphQL::Schema
2
3
  query(Types::QueryType)
3
4
 
@@ -38,3 +39,4 @@ class <%= schema_name %> < GraphQL::Schema
38
39
  # GraphQL::Batch setup:
39
40
  use GraphQL::Batch
40
41
  <% end %>end
42
+ <% end -%>
@@ -1,5 +1,7 @@
1
+ <% module_namespacing_when_supported do -%>
1
2
  module Types
2
3
  class <%= type_ruby_name.split('::')[-1] %> < Types::BaseUnion
3
- <% if possible_types.any? %> possible_types [<%= normalized_possible_types.join(", ") %>]
4
+ <% if possible_types.any? %> possible_types <%= normalized_possible_types.join(", ") %>
4
5
  <% end %> end
5
6
  end
7
+ <% end -%>
@@ -21,6 +21,14 @@ module GraphQL
21
21
  class RequiredImplementationMissingError < Error
22
22
  end
23
23
 
24
+ class << self
25
+ def default_parser
26
+ @default_parser ||= GraphQL::Language::Parser
27
+ end
28
+
29
+ attr_writer :default_parser
30
+ end
31
+
24
32
  # Turn a query string or schema definition into an AST
25
33
  # @param graphql_string [String] a GraphQL query string or schema definition
26
34
  # @return [GraphQL::Language::Nodes::Document]
@@ -61,6 +69,14 @@ module GraphQL
61
69
  end
62
70
  end
63
71
  end
72
+
73
+ module StringMatchBackport
74
+ refine String do
75
+ def match?(pattern)
76
+ self =~ pattern
77
+ end
78
+ end
79
+ end
64
80
  end
65
81
 
66
82
  # Order matters for these:
@@ -3,14 +3,14 @@ module GraphQL
3
3
  # @api deprecated
4
4
  class Argument
5
5
  include GraphQL::Define::InstanceDefinable
6
- accepts_definitions :name, :type, :description, :default_value, :as, :prepare, :method_access
6
+ accepts_definitions :name, :type, :description, :default_value, :as, :prepare, :method_access, :deprecation_reason
7
7
  attr_reader :default_value
8
- attr_accessor :description, :name, :as
8
+ attr_accessor :description, :name, :as, :deprecation_reason
9
9
  attr_accessor :ast_node
10
10
  attr_accessor :method_access
11
11
  alias :graphql_name :name
12
12
 
13
- ensure_defined(:name, :description, :default_value, :type=, :type, :as, :expose_as, :prepare, :method_access)
13
+ ensure_defined(:name, :description, :default_value, :type=, :type, :as, :expose_as, :prepare, :method_access, :deprecation_reason)
14
14
 
15
15
  # @api private
16
16
  module DefaultPrepare
@@ -15,7 +15,8 @@ module GraphQL
15
15
  when "validate", "analyze_query", "execute_query", "execute_query_lazy"
16
16
  metadata[:query] || metadata[:queries]
17
17
  when "execute_field", "execute_field_lazy"
18
- metadata[:context]
18
+ # The interpreter passes `query:`, legacy passes `context:`
19
+ metadata[:context] || ((q = metadata[:query]) && q.context)
19
20
  else
20
21
  # Custom key, no backtrace data for this
21
22
  nil
@@ -2,9 +2,9 @@
2
2
  module GraphQL
3
3
  module Define
4
4
  module AssignGlobalIdField
5
- def self.call(type_defn, field_name)
5
+ def self.call(type_defn, field_name, **field_kwargs)
6
6
  resolve = GraphQL::Relay::GlobalIdResolve.new(type: type_defn)
7
- GraphQL::Define::AssignObjectField.call(type_defn, field_name, type: GraphQL::ID_TYPE.to_non_null_type, resolve: resolve)
7
+ GraphQL::Define::AssignObjectField.call(type_defn, field_name, **field_kwargs, type: GraphQL::ID_TYPE.to_non_null_type, resolve: resolve)
8
8
  end
9
9
  end
10
10
  end
@@ -99,6 +99,10 @@ module GraphQL
99
99
  def type_class
100
100
  metadata[:type_class]
101
101
  end
102
+
103
+ def get_argument(argument_name)
104
+ arguments[argument_name]
105
+ end
102
106
  end
103
107
  end
104
108
 
@@ -93,6 +93,16 @@ module GraphQL
93
93
  tracer.trace("execute_query_lazy", {multiplex: multiplex, query: query}) do
94
94
  Interpreter::Resolve.resolve_all(final_values)
95
95
  end
96
+ queries.each do |query|
97
+ runtime = query.context.namespace(:interpreter)[:runtime]
98
+ if runtime
99
+ runtime.delete_interpreter_context(:current_path)
100
+ runtime.delete_interpreter_context(:current_field)
101
+ runtime.delete_interpreter_context(:current_object)
102
+ runtime.delete_interpreter_context(:current_arguments)
103
+ end
104
+ end
105
+ nil
96
106
  end
97
107
 
98
108
  class ListResultFailedError < GraphQL::Error
@@ -24,7 +24,7 @@ module GraphQL
24
24
  # @return [Hash{Symbol => ArgumentValue}]
25
25
  attr_reader :argument_values
26
26
 
27
- def_delegators :@keyword_arguments, :key?, :[], :keys, :each, :values
27
+ def_delegators :@keyword_arguments, :key?, :[], :fetch, :keys, :each, :values
28
28
  def_delegators :@argument_values, :each_value
29
29
 
30
30
  def inspect
@@ -43,23 +43,25 @@ module GraphQL
43
43
  # might be stored up in lazies.
44
44
  # @return [void]
45
45
  def run_eager
46
-
47
46
  root_operation = query.selected_operation
48
47
  root_op_type = root_operation.operation_type || "query"
49
48
  root_type = schema.root_type_for_operation(root_op_type)
50
49
  path = []
51
- @interpreter_context[:current_object] = query.root_value
52
- @interpreter_context[:current_path] = path
50
+ set_interpreter_context(:current_object, query.root_value)
51
+ set_interpreter_context(:current_path, path)
53
52
  object_proxy = authorized_new(root_type, query.root_value, context, path)
54
53
  object_proxy = schema.sync_lazy(object_proxy)
55
54
  if object_proxy.nil?
56
55
  # Root .authorized? returned false.
57
56
  write_in_response(path, nil)
58
- nil
59
57
  else
60
58
  evaluate_selections(path, context.scoped_context, object_proxy, root_type, root_operation.selections, root_operation_type: root_op_type)
61
- nil
62
59
  end
60
+ delete_interpreter_context(:current_path)
61
+ delete_interpreter_context(:current_field)
62
+ delete_interpreter_context(:current_object)
63
+ delete_interpreter_context(:current_arguments)
64
+ nil
63
65
  end
64
66
 
65
67
  def gather_selections(owner_object, owner_type, selections, selections_by_name)
@@ -117,8 +119,8 @@ module GraphQL
117
119
  end
118
120
 
119
121
  def evaluate_selections(path, scoped_context, owner_object, owner_type, selections, root_operation_type: nil)
120
- @interpreter_context[:current_object] = owner_object
121
- @interpreter_context[:current_path] = path
122
+ set_interpreter_context(:current_object, owner_object)
123
+ set_interpreter_context(:current_path, path)
122
124
  selections_by_name = {}
123
125
  gather_selections(owner_object, owner_type, selections, selections_by_name)
124
126
  selections_by_name.each do |result_name, field_ast_nodes_or_ast_node|
@@ -157,8 +159,8 @@ module GraphQL
157
159
  # to propagate `null`
158
160
  set_type_at_path(next_path, return_type)
159
161
  # Set this before calling `run_with_directives`, so that the directive can have the latest path
160
- @interpreter_context[:current_path] = next_path
161
- @interpreter_context[:current_field] = field_defn
162
+ set_interpreter_context(:current_path, next_path)
163
+ set_interpreter_context(:current_field, field_defn)
162
164
 
163
165
  context.scoped_context = scoped_context
164
166
  object = owner_object
@@ -170,13 +172,13 @@ module GraphQL
170
172
  begin
171
173
  kwarg_arguments = arguments(object, field_defn, ast_node)
172
174
  rescue GraphQL::ExecutionError => e
173
- continue_value(next_path, e, field_defn, return_type.non_null?, ast_node)
175
+ continue_value(next_path, e, owner_type, field_defn, return_type.non_null?, ast_node)
174
176
  next
175
177
  end
176
178
 
177
179
  after_lazy(kwarg_arguments, owner: owner_type, field: field_defn, path: next_path, scoped_context: context.scoped_context, owner_object: object, arguments: kwarg_arguments) do |resolved_arguments|
178
180
  if resolved_arguments.is_a? GraphQL::ExecutionError
179
- continue_value(next_path, resolved_arguments, field_defn, return_type.non_null?, ast_node)
181
+ continue_value(next_path, resolved_arguments, owner_type, field_defn, return_type.non_null?, ast_node)
180
182
  next
181
183
  end
182
184
 
@@ -206,7 +208,7 @@ module GraphQL
206
208
  end
207
209
  end
208
210
 
209
- @interpreter_context[:current_arguments] = kwarg_arguments
211
+ set_interpreter_context(:current_arguments, kwarg_arguments)
210
212
 
211
213
  # Optimize for the case that field is selected only once
212
214
  if field_ast_nodes.nil? || field_ast_nodes.size == 1
@@ -228,12 +230,12 @@ module GraphQL
228
230
  err
229
231
  end
230
232
  after_lazy(app_result, owner: owner_type, field: field_defn, path: next_path, scoped_context: context.scoped_context, owner_object: object, arguments: kwarg_arguments) do |inner_result|
231
- continue_value = continue_value(next_path, inner_result, field_defn, return_type.non_null?, ast_node)
233
+ continue_value = continue_value(next_path, inner_result, owner_type, field_defn, return_type.non_null?, ast_node)
232
234
  if RawValue === continue_value
233
235
  # Write raw value directly to the response without resolving nested objects
234
236
  write_in_response(next_path, continue_value.resolve)
235
237
  elsif HALT != continue_value
236
- continue_field(next_path, continue_value, field_defn, return_type, ast_node, next_selections, false, object, kwarg_arguments)
238
+ continue_field(next_path, continue_value, owner_type, field_defn, return_type, ast_node, next_selections, false, object, kwarg_arguments)
237
239
  end
238
240
  end
239
241
  end
@@ -251,10 +253,9 @@ module GraphQL
251
253
  end
252
254
 
253
255
  HALT = Object.new
254
- def continue_value(path, value, field, is_non_null, ast_node)
256
+ def continue_value(path, value, parent_type, field, is_non_null, ast_node)
255
257
  if value.nil?
256
258
  if is_non_null
257
- parent_type = field.owner_type
258
259
  err = parent_type::InvalidNullError.new(parent_type, field, value)
259
260
  write_invalid_null_in_response(path, err)
260
261
  else
@@ -282,7 +283,7 @@ module GraphQL
282
283
  err
283
284
  end
284
285
 
285
- continue_value(path, next_value, field, is_non_null, ast_node)
286
+ continue_value(path, next_value, parent_type, field, is_non_null, ast_node)
286
287
  elsif GraphQL::Execution::Execute::SKIP == value
287
288
  HALT
288
289
  else
@@ -298,49 +299,49 @@ module GraphQL
298
299
  # Location information from `path` and `ast_node`.
299
300
  #
300
301
  # @return [Lazy, Array, Hash, Object] Lazy, Array, and Hash are all traversed to resolve lazy values later
301
- def continue_field(path, value, field, type, ast_node, next_selections, is_non_null, owner_object, arguments) # rubocop:disable Metrics/ParameterLists
302
- case type.kind.name
302
+ def continue_field(path, value, owner_type, field, current_type, ast_node, next_selections, is_non_null, owner_object, arguments) # rubocop:disable Metrics/ParameterLists
303
+ case current_type.kind.name
303
304
  when "SCALAR", "ENUM"
304
- r = type.coerce_result(value, context)
305
+ r = current_type.coerce_result(value, context)
305
306
  write_in_response(path, r)
306
307
  r
307
308
  when "UNION", "INTERFACE"
308
- resolved_type_or_lazy, resolved_value = resolve_type(type, value, path)
309
+ resolved_type_or_lazy, resolved_value = resolve_type(current_type, value, path)
309
310
  resolved_value ||= value
310
311
 
311
- after_lazy(resolved_type_or_lazy, owner: type, path: path, scoped_context: context.scoped_context, field: field, owner_object: owner_object, arguments: arguments, trace: false) do |resolved_type|
312
- possible_types = query.possible_types(type)
312
+ after_lazy(resolved_type_or_lazy, owner: current_type, path: path, scoped_context: context.scoped_context, field: field, owner_object: owner_object, arguments: arguments, trace: false) do |resolved_type|
313
+ possible_types = query.possible_types(current_type)
313
314
 
314
315
  if !possible_types.include?(resolved_type)
315
316
  parent_type = field.owner_type
316
- err_class = type::UnresolvedTypeError
317
+ err_class = current_type::UnresolvedTypeError
317
318
  type_error = err_class.new(resolved_value, field, parent_type, resolved_type, possible_types)
318
319
  schema.type_error(type_error, context)
319
320
  write_in_response(path, nil)
320
321
  nil
321
322
  else
322
- continue_field(path, resolved_value, field, resolved_type, ast_node, next_selections, is_non_null, owner_object, arguments)
323
+ continue_field(path, resolved_value, owner_type, field, resolved_type, ast_node, next_selections, is_non_null, owner_object, arguments)
323
324
  end
324
325
  end
325
326
  when "OBJECT"
326
327
  object_proxy = begin
327
- authorized_new(type, value, context, path)
328
+ authorized_new(current_type, value, context, path)
328
329
  rescue GraphQL::ExecutionError => err
329
330
  err
330
331
  end
331
- after_lazy(object_proxy, owner: type, path: path, scoped_context: context.scoped_context, field: field, owner_object: owner_object, arguments: arguments, trace: false) do |inner_object|
332
- continue_value = continue_value(path, inner_object, field, is_non_null, ast_node)
332
+ after_lazy(object_proxy, owner: current_type, path: path, scoped_context: context.scoped_context, field: field, owner_object: owner_object, arguments: arguments, trace: false) do |inner_object|
333
+ continue_value = continue_value(path, inner_object, owner_type, field, is_non_null, ast_node)
333
334
  if HALT != continue_value
334
335
  response_hash = {}
335
336
  write_in_response(path, response_hash)
336
- evaluate_selections(path, context.scoped_context, continue_value, type, next_selections)
337
+ evaluate_selections(path, context.scoped_context, continue_value, current_type, next_selections)
337
338
  response_hash
338
339
  end
339
340
  end
340
341
  when "LIST"
341
342
  response_list = []
342
343
  write_in_response(path, response_list)
343
- inner_type = type.of_type
344
+ inner_type = current_type.of_type
344
345
  idx = 0
345
346
  scoped_context = context.scoped_context
346
347
  begin
@@ -352,9 +353,9 @@ module GraphQL
352
353
  set_type_at_path(next_path, inner_type)
353
354
  # This will update `response_list` with the lazy
354
355
  after_lazy(inner_value, owner: inner_type, path: next_path, scoped_context: scoped_context, field: field, owner_object: owner_object, arguments: arguments) do |inner_inner_value|
355
- continue_value = continue_value(next_path, inner_inner_value, field, inner_type.non_null?, ast_node)
356
+ continue_value = continue_value(next_path, inner_inner_value, owner_type, field, inner_type.non_null?, ast_node)
356
357
  if HALT != continue_value
357
- continue_field(next_path, continue_value, field, inner_type, ast_node, next_selections, false, owner_object, arguments)
358
+ continue_field(next_path, continue_value, owner_type, field, inner_type, ast_node, next_selections, false, owner_object, arguments)
358
359
  end
359
360
  end
360
361
  end
@@ -371,12 +372,12 @@ module GraphQL
371
372
 
372
373
  response_list
373
374
  when "NON_NULL"
374
- inner_type = type.of_type
375
+ inner_type = current_type.of_type
375
376
  # Don't `set_type_at_path` because we want the static type,
376
377
  # we're going to use that to determine whether a `nil` should be propagated or not.
377
- continue_field(path, value, field, inner_type, ast_node, next_selections, true, owner_object, arguments)
378
+ continue_field(path, value, owner_type, field, inner_type, ast_node, next_selections, true, owner_object, arguments)
378
379
  else
379
- raise "Invariant: Unhandled type kind #{type.kind} (#{type})"
380
+ raise "Invariant: Unhandled type kind #{current_type.kind} (#{current_type})"
380
381
  end
381
382
  end
382
383
 
@@ -420,16 +421,16 @@ module GraphQL
420
421
  # @param trace [Boolean] If `false`, don't wrap this with field tracing
421
422
  # @return [GraphQL::Execution::Lazy, Object] If loading `object` will be deferred, it's a wrapper over it.
422
423
  def after_lazy(lazy_obj, owner:, field:, path:, scoped_context:, owner_object:, arguments:, eager: false, trace: true, &block)
423
- @interpreter_context[:current_object] = owner_object
424
- @interpreter_context[:current_arguments] = arguments
425
- @interpreter_context[:current_path] = path
426
- @interpreter_context[:current_field] = field
424
+ set_interpreter_context(:current_object, owner_object)
425
+ set_interpreter_context(:current_arguments, arguments)
426
+ set_interpreter_context(:current_path, path)
427
+ set_interpreter_context(:current_field, field)
427
428
  if schema.lazy?(lazy_obj)
428
429
  lazy = GraphQL::Execution::Lazy.new(path: path, field: field) do
429
- @interpreter_context[:current_path] = path
430
- @interpreter_context[:current_field] = field
431
- @interpreter_context[:current_object] = owner_object
432
- @interpreter_context[:current_arguments] = arguments
430
+ set_interpreter_context(:current_path, path)
431
+ set_interpreter_context(:current_field, field)
432
+ set_interpreter_context(:current_object, owner_object)
433
+ set_interpreter_context(:current_arguments, arguments)
433
434
  context.scoped_context = scoped_context
434
435
  # Wrap the execution of _this_ method with tracing,
435
436
  # but don't wrap the continuation below
@@ -461,8 +462,9 @@ module GraphQL
461
462
  end
462
463
 
463
464
  def arguments(graphql_object, arg_owner, ast_node)
464
- # Don't cache arguments if field extras are requested since extras mutate the argument data structure
465
- if arg_owner.arguments_statically_coercible? && (!arg_owner.is_a?(GraphQL::Schema::Field) || arg_owner.extras.empty?)
465
+ # Don't cache arguments if field extras or extensions are requested since they can mutate the argument data structure
466
+ if arg_owner.arguments_statically_coercible? &&
467
+ (!arg_owner.is_a?(GraphQL::Schema::Field) || (arg_owner.extras.empty? && arg_owner.extensions.empty?))
466
468
  query.arguments_for(ast_node, arg_owner)
467
469
  else
468
470
  # The arguments must be prepared in the context of the given object
@@ -539,6 +541,18 @@ module GraphQL
539
541
  res && res[:__dead]
540
542
  end
541
543
 
544
+ # Set this pair in the Query context, but also in the interpeter namespace,
545
+ # for compatibility.
546
+ def set_interpreter_context(key, value)
547
+ @interpreter_context[key] = value
548
+ @context[key] = value
549
+ end
550
+
551
+ def delete_interpreter_context(key)
552
+ @interpreter_context.delete(key)
553
+ @context.delete(key)
554
+ end
555
+
542
556
  def resolve_type(type, value, path)
543
557
  trace_payload = { context: context, type: type, object: value, path: path }
544
558
  resolved_type, resolved_value = query.trace("resolve_type", trace_payload) do