graphql 1.11.1 → 1.11.6

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 (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