graphql 1.10.13 → 1.11.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.
Files changed (49) hide show
  1. checksums.yaml +4 -4
  2. data/lib/generators/graphql/templates/graphql_controller.erb +11 -9
  3. data/lib/graphql.rb +3 -3
  4. data/lib/graphql/directive.rb +4 -0
  5. data/lib/graphql/execution/interpreter.rb +1 -1
  6. data/lib/graphql/execution/interpreter/runtime.rb +6 -4
  7. data/lib/graphql/execution/multiplex.rb +1 -2
  8. data/lib/graphql/field.rb +4 -0
  9. data/lib/graphql/input_object_type.rb +4 -0
  10. data/lib/graphql/introspection/schema_type.rb +3 -3
  11. data/lib/graphql/invalid_null_error.rb +18 -0
  12. data/lib/graphql/language/nodes.rb +1 -0
  13. data/lib/graphql/language/visitor.rb +2 -2
  14. data/lib/graphql/pagination/connection.rb +18 -13
  15. data/lib/graphql/pagination/connections.rb +17 -4
  16. data/lib/graphql/query.rb +1 -2
  17. data/lib/graphql/schema.rb +22 -16
  18. data/lib/graphql/schema/build_from_definition.rb +7 -12
  19. data/lib/graphql/schema/build_from_definition/resolve_map.rb +3 -1
  20. data/lib/graphql/schema/enum_value.rb +1 -0
  21. data/lib/graphql/schema/field.rb +63 -77
  22. data/lib/graphql/schema/field/connection_extension.rb +42 -32
  23. data/lib/graphql/schema/loader.rb +19 -1
  24. data/lib/graphql/schema/member/has_arguments.rb +3 -1
  25. data/lib/graphql/schema/member/has_fields.rb +15 -5
  26. data/lib/graphql/schema/mutation.rb +4 -0
  27. data/lib/graphql/schema/object.rb +1 -1
  28. data/lib/graphql/schema/resolver.rb +20 -0
  29. data/lib/graphql/schema/resolver/has_payload_type.rb +2 -1
  30. data/lib/graphql/schema/subscription.rb +1 -1
  31. data/lib/graphql/schema/union.rb +29 -0
  32. data/lib/graphql/schema/warden.rb +0 -1
  33. data/lib/graphql/static_validation/literal_validator.rb +7 -7
  34. data/lib/graphql/static_validation/rules/arguments_are_defined.rb +1 -1
  35. data/lib/graphql/static_validation/rules/required_arguments_are_present.rb +2 -2
  36. data/lib/graphql/static_validation/rules/required_input_object_attributes_are_present.rb +1 -2
  37. data/lib/graphql/static_validation/rules/variables_are_used_and_defined.rb +4 -2
  38. data/lib/graphql/subscriptions.rb +41 -8
  39. data/lib/graphql/subscriptions/action_cable_subscriptions.rb +66 -11
  40. data/lib/graphql/subscriptions/broadcast_analyzer.rb +84 -0
  41. data/lib/graphql/subscriptions/default_subscription_resolve_extension.rb +21 -0
  42. data/lib/graphql/subscriptions/event.rb +16 -1
  43. data/lib/graphql/subscriptions/serialize.rb +22 -4
  44. data/lib/graphql/subscriptions/subscription_root.rb +3 -1
  45. data/lib/graphql/tracing.rb +1 -27
  46. data/lib/graphql/tracing/platform_tracing.rb +25 -15
  47. data/lib/graphql/tracing/statsd_tracing.rb +14 -14
  48. data/lib/graphql/version.rb +1 -1
  49. metadata +4 -2
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 617464390cac424fae4c09fe3db0abbaa6e0d980cb349a9b8e51c4d84b2cb662
4
- data.tar.gz: 4abf2fbac2606f6e8b493ca379a11569597500433bba51c8acbc7fdb891a3272
3
+ metadata.gz: 8f64724e3b46476cf0a622ef5d5d1beb4360c7d5de031907d5173cb462928ee4
4
+ data.tar.gz: 9b8098bab2bfdc704bf98dc011a452f1bce8c480c9435f1b37a79430ee81bc06
5
5
  SHA512:
6
- metadata.gz: de0cca8810127cf5649e68f6968e970131d7f34a0b1cd33230b79e56ae7e311134f96f588820caf273ef529c89e12a8df8c9afe213dbb9477cb798923044beb7
7
- data.tar.gz: 30014092e85f256ace16b3635ed9e4e2c8a081904bca4e1e6197d0fff07f13d7997968ffc8aaee9de576d5372e219d432a8a62ae3406d81a61f9435debeaa247
6
+ metadata.gz: 6dabc15fe0688fc37233e23f5bc5647bf55ad176456257c088e15a87f7fabc07b6da43e86efcd9e982ecfc8b47c6eca331a0ced9a82f20076c21aa4ccf20f223
7
+ data.tar.gz: d98a3193ab5759d206aabf9db378c38c669cbc2752f4b8908484fcf2cbee9012f00721403ffe999cd19e43016a6b27bd2c0f5f1dc602b93543772f1e7a4791b5
@@ -5,7 +5,7 @@ class GraphqlController < ApplicationController
5
5
  # protect_from_forgery with: :null_session
6
6
 
7
7
  def execute
8
- variables = ensure_hash(params[:variables])
8
+ variables = prepare_variables(params[:variables])
9
9
  query = params[:query]
10
10
  operation_name = params[:operationName]
11
11
  context = {
@@ -21,21 +21,23 @@ class GraphqlController < ApplicationController
21
21
 
22
22
  private
23
23
 
24
- # Handle form data, JSON body, or a blank value
25
- def ensure_hash(ambiguous_param)
26
- case ambiguous_param
24
+ # Handle variables in form data, JSON body, or a blank value
25
+ def prepare_variables(variables_param)
26
+ case variables_param
27
27
  when String
28
- if ambiguous_param.present?
29
- ensure_hash(JSON.parse(ambiguous_param))
28
+ if variables_param.present?
29
+ JSON.parse(variables_param) || {}
30
30
  else
31
31
  {}
32
32
  end
33
- when Hash, ActionController::Parameters
34
- ambiguous_param
33
+ when Hash
34
+ variables_param
35
+ when ActionController::Parameters
36
+ variables_param.to_unsafe_hash # GraphQL-Ruby will validate name and type of incoming variables.
35
37
  when nil
36
38
  {}
37
39
  else
38
- raise ArgumentError, "Unexpected parameter: #{ambiguous_param}"
40
+ raise ArgumentError, "Unexpected parameter: #{variables_param}"
39
41
  end
40
42
  end
41
43
 
@@ -91,13 +91,13 @@ require "graphql/analysis"
91
91
  require "graphql/tracing"
92
92
  require "graphql/dig"
93
93
  require "graphql/execution"
94
+ require "graphql/runtime_type_error"
95
+ require "graphql/unresolved_type_error"
96
+ require "graphql/invalid_null_error"
94
97
  require "graphql/schema"
95
98
  require "graphql/query"
96
99
  require "graphql/directive"
97
100
  require "graphql/execution"
98
- require "graphql/runtime_type_error"
99
- require "graphql/unresolved_type_error"
100
- require "graphql/invalid_null_error"
101
101
  require "graphql/types"
102
102
  require "graphql/relay"
103
103
  require "graphql/boolean_type"
@@ -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
 
@@ -26,7 +26,7 @@ module GraphQL
26
26
  schema_class.query_execution_strategy(GraphQL::Execution::Interpreter)
27
27
  schema_class.mutation_execution_strategy(GraphQL::Execution::Interpreter)
28
28
  schema_class.subscription_execution_strategy(GraphQL::Execution::Interpreter)
29
-
29
+ schema_class.add_subscription_extension_if_necessary
30
30
  GraphQL::Schema::Object.include(HandlesRawValue)
31
31
  end
32
32
 
@@ -254,7 +254,8 @@ module GraphQL
254
254
  def continue_value(path, value, field, is_non_null, ast_node)
255
255
  if value.nil?
256
256
  if is_non_null
257
- err = field.owner::InvalidNullError.new(field.owner, field, value)
257
+ parent_type = field.owner_type
258
+ err = parent_type::InvalidNullError.new(parent_type, field, value)
258
259
  write_invalid_null_in_response(path, err)
259
260
  else
260
261
  write_in_response(path, nil)
@@ -311,7 +312,7 @@ module GraphQL
311
312
  possible_types = query.possible_types(type)
312
313
 
313
314
  if !possible_types.include?(resolved_type)
314
- parent_type = field.owner
315
+ parent_type = field.owner_type
315
316
  err_class = type::UnresolvedTypeError
316
317
  type_error = err_class.new(resolved_value, field, parent_type, resolved_type, possible_types)
317
318
  schema.type_error(type_error, context)
@@ -460,8 +461,9 @@ module GraphQL
460
461
  end
461
462
 
462
463
  def arguments(graphql_object, arg_owner, ast_node)
463
- # Don't cache arguments if field extras are requested since extras mutate the argument data structure
464
- if arg_owner.arguments_statically_coercible? && (!arg_owner.is_a?(GraphQL::Schema::Field) || arg_owner.extras.empty?)
464
+ # Don't cache arguments if field extras or extensions are requested since they can mutate the argument data structure
465
+ if arg_owner.arguments_statically_coercible? &&
466
+ (!arg_owner.is_a?(GraphQL::Schema::Field) || (arg_owner.extras.empty? && arg_owner.extensions.empty?))
465
467
  query.arguments_for(ast_node, arg_owner)
466
468
  else
467
469
  # The arguments must be prepared in the context of the given object
@@ -34,8 +34,7 @@ module GraphQL
34
34
  @schema = schema
35
35
  @queries = queries
36
36
  @context = context
37
- # TODO remove support for global tracers
38
- @tracers = schema.tracers + GraphQL::Tracing.tracers + (context[:tracers] || [])
37
+ @tracers = schema.tracers + (context[:tracers] || [])
39
38
  # Support `context: {backtrace: true}`
40
39
  if context[:backtrace] && !@tracers.include?(GraphQL::Backtrace::Tracer)
41
40
  @tracers << GraphQL::Backtrace::Tracer
@@ -207,6 +207,10 @@ module GraphQL
207
207
  metadata[:type_class]
208
208
  end
209
209
 
210
+ def get_argument(argument_name)
211
+ arguments[argument_name]
212
+ end
213
+
210
214
  private
211
215
 
212
216
  def build_default_resolver
@@ -58,6 +58,10 @@ module GraphQL
58
58
  result
59
59
  end
60
60
 
61
+ def get_argument(argument_name)
62
+ arguments[argument_name]
63
+ end
64
+
61
65
  private
62
66
 
63
67
  def coerce_non_null_input(value, ctx)
@@ -9,9 +9,9 @@ module GraphQL
9
9
  "query, mutation, and subscription operations."
10
10
 
11
11
  field :types, [GraphQL::Schema::LateBoundType.new("__Type")], "A list of all types supported by this server.", null: false
12
- field :queryType, GraphQL::Schema::LateBoundType.new("__Type"), "The type that query operations will be rooted at.", null: false
13
- field :mutationType, GraphQL::Schema::LateBoundType.new("__Type"), "If this server supports mutation, the type that mutation operations will be rooted at.", null: true
14
- field :subscriptionType, GraphQL::Schema::LateBoundType.new("__Type"), "If this server support subscription, the type that subscription operations will be rooted at.", null: true
12
+ field :query_type, GraphQL::Schema::LateBoundType.new("__Type"), "The type that query operations will be rooted at.", null: false
13
+ field :mutation_type, GraphQL::Schema::LateBoundType.new("__Type"), "If this server supports mutation, the type that mutation operations will be rooted at.", null: true
14
+ field :subscription_type, GraphQL::Schema::LateBoundType.new("__Type"), "If this server support subscription, the type that subscription operations will be rooted at.", null: true
15
15
  field :directives, [GraphQL::Schema::LateBoundType.new("__Directive")], "A list of all directives supported by this server.", null: false
16
16
 
17
17
  def types
@@ -28,5 +28,23 @@ module GraphQL
28
28
  def parent_error?
29
29
  false
30
30
  end
31
+
32
+ class << self
33
+ attr_accessor :parent_class
34
+
35
+ def subclass_for(parent_class)
36
+ subclass = Class.new(self)
37
+ subclass.parent_class = parent_class
38
+ subclass
39
+ end
40
+
41
+ def inspect
42
+ if name.nil? && parent_class.respond_to?(:mutation) && (mutation = parent_class.mutation)
43
+ "#{mutation.inspect}::#{parent_class.graphql_name}::InvalidNullError"
44
+ else
45
+ super
46
+ end
47
+ end
48
+ end
31
49
  end
32
50
  end
@@ -524,6 +524,7 @@ module GraphQL
524
524
 
525
525
  # Usage of a variable in a query. Name does _not_ include `$`.
526
526
  class VariableIdentifier < NameOnlyNode
527
+ self.children_method_name = :value
527
528
  end
528
529
 
529
530
  class SchemaDefinition < AbstractNode
@@ -89,7 +89,7 @@ module GraphQL
89
89
  # @param parent [GraphQL::Language::Nodes::AbstractNode, nil] the previously-visited node, or `nil` if this is the root node.
90
90
  # @return [Array, nil] If there were modifications, it returns an array of new nodes, otherwise, it returns `nil`.
91
91
  def on_abstract_node(node, parent)
92
- if node == DELETE_NODE
92
+ if node.equal?(DELETE_NODE)
93
93
  # This might be passed to `super(DELETE_NODE, ...)`
94
94
  # by a user hook, don't want to keep visiting in that case.
95
95
  nil
@@ -179,7 +179,7 @@ module GraphQL
179
179
  # The user-provided hook returned a new node.
180
180
  new_parent = new_parent && new_parent.replace_child(node, new_node)
181
181
  return new_node, new_parent
182
- elsif new_node == DELETE_NODE
182
+ elsif new_node.equal?(DELETE_NODE)
183
183
  # The user-provided hook requested to remove this node
184
184
  new_parent = new_parent && new_parent.delete_child(node)
185
185
  return nil, new_parent
@@ -15,17 +15,15 @@ module GraphQL
15
15
  class PaginationImplementationMissingError < GraphQL::Error
16
16
  end
17
17
 
18
- # @return [Class] The class to use for wrapping items as `edges { ... }`. Defaults to `Connection::Edge`
19
- def self.edge_class
20
- self::Edge
21
- end
22
-
23
18
  # @return [Object] A list object, from the application. This is the unpaginated value passed into the connection.
24
19
  attr_reader :items
25
20
 
26
21
  # @return [GraphQL::Query::Context]
27
22
  attr_accessor :context
28
23
 
24
+ # @return [Object] the object this collection belongs to
25
+ attr_accessor :parent
26
+
29
27
  # Raw access to client-provided values. (`max_page_size` not applied to first or last.)
30
28
  attr_accessor :before_value, :after_value, :first_value, :last_value
31
29
 
@@ -49,19 +47,21 @@ module GraphQL
49
47
 
50
48
  # @param items [Object] some unpaginated collection item, like an `Array` or `ActiveRecord::Relation`
51
49
  # @param context [Query::Context]
50
+ # @param parent [Object] The object this collection belongs to
52
51
  # @param first [Integer, nil] The limit parameter from the client, if it provided one
53
52
  # @param after [String, nil] A cursor for pagination, if the client provided one
54
53
  # @param last [Integer, nil] Limit parameter from the client, if provided
55
54
  # @param before [String, nil] A cursor for pagination, if the client provided one.
56
55
  # @param max_page_size [Integer, nil] A configured value to cap the result size. Applied as `first` if neither first or last are given.
57
- def initialize(items, context: nil, first: nil, after: nil, max_page_size: :not_given, last: nil, before: nil)
56
+ def initialize(items, parent: nil, context: nil, first: nil, after: nil, max_page_size: :not_given, last: nil, before: nil, edge_class: nil)
58
57
  @items = items
58
+ @parent = parent
59
59
  @context = context
60
60
  @first_value = first
61
61
  @after_value = after
62
62
  @last_value = last
63
63
  @before_value = before
64
-
64
+ @edge_class = edge_class || self.class::Edge
65
65
  # This is only true if the object was _initialized_ with an override
66
66
  # or if one is assigned later.
67
67
  @has_max_page_size_override = max_page_size != :not_given
@@ -112,9 +112,12 @@ module GraphQL
112
112
 
113
113
  # @return [Array<Edge>] {nodes}, but wrapped with Edge instances
114
114
  def edges
115
- @edges ||= nodes.map { |n| self.class.edge_class.new(n, self) }
115
+ @edges ||= nodes.map { |n| @edge_class.new(n, self) }
116
116
  end
117
117
 
118
+ # @return [Class] A wrapper class for edges of this connection
119
+ attr_accessor :edge_class
120
+
118
121
  # @return [Array<Object>] A slice of {items}, constrained by {@first_value}/{@after_value}/{@last_value}/{@before_value}
119
122
  def nodes
120
123
  raise PaginationImplementationMissingError, "Implement #{self.class}#nodes to paginate `@items`"
@@ -185,17 +188,19 @@ module GraphQL
185
188
  # A wrapper around paginated items. It includes a {cursor} for pagination
186
189
  # and could be extended with custom relationship-level data.
187
190
  class Edge
188
- def initialize(item, connection)
191
+ attr_reader :node
192
+
193
+ def initialize(node, connection)
189
194
  @connection = connection
190
- @item = item
195
+ @node = node
191
196
  end
192
197
 
193
- def node
194
- @item
198
+ def parent
199
+ @connection.parent
195
200
  end
196
201
 
197
202
  def cursor
198
- @connection.cursor_for(@item)
203
+ @cursor ||= @connection.cursor_for(@node)
199
204
  end
200
205
  end
201
206
  end
@@ -65,29 +65,42 @@ module GraphQL
65
65
 
66
66
  # Used by the runtime to wrap values in connection wrappers.
67
67
  # @api Private
68
- def wrap(field, object, arguments, context, wrappers: all_wrappers)
68
+ def wrap(field, parent, items, arguments, context, wrappers: all_wrappers)
69
69
  impl = nil
70
70
 
71
- object.class.ancestors.each { |cls|
71
+ items.class.ancestors.each { |cls|
72
72
  impl = wrappers[cls]
73
73
  break if impl
74
74
  }
75
75
 
76
76
  if impl.nil?
77
- raise ImplementationMissingError, "Couldn't find a connection wrapper for #{object.class} during #{field.path} (#{object.inspect})"
77
+ raise ImplementationMissingError, "Couldn't find a connection wrapper for #{items.class} during #{field.path} (#{items.inspect})"
78
78
  end
79
79
 
80
80
  impl.new(
81
- object,
81
+ items,
82
82
  context: context,
83
+ parent: parent,
83
84
  max_page_size: field.max_page_size || context.schema.default_max_page_size,
84
85
  first: arguments[:first],
85
86
  after: arguments[:after],
86
87
  last: arguments[:last],
87
88
  before: arguments[:before],
89
+ edge_class: edge_class_for_field(field),
88
90
  )
89
91
  end
90
92
 
93
+ # use an override if there is one
94
+ # @api private
95
+ def edge_class_for_field(field)
96
+ conn_type = field.type.unwrap
97
+ conn_type_edge_type = conn_type.respond_to?(:edge_class) && conn_type.edge_class
98
+ if conn_type_edge_type && conn_type_edge_type != Relay::Edge
99
+ conn_type_edge_type
100
+ else
101
+ nil
102
+ end
103
+ end
91
104
  protected
92
105
 
93
106
  attr_reader :wrappers
@@ -96,8 +96,7 @@ module GraphQL
96
96
  @fragments = nil
97
97
  @operations = nil
98
98
  @validate = validate
99
- # TODO: remove support for global tracers
100
- @tracers = schema.tracers + GraphQL::Tracing.tracers + (context ? context.fetch(:tracers, []) : [])
99
+ @tracers = schema.tracers + (context ? context.fetch(:tracers, []) : [])
101
100
  # Support `ctx[:backtrace] = true` for wrapping backtraces
102
101
  if context && context[:backtrace] && !@tracers.include?(GraphQL::Backtrace::Tracer)
103
102
  @tracers << GraphQL::Backtrace::Tracer
@@ -127,7 +127,7 @@ module GraphQL
127
127
  end
128
128
  end
129
129
 
130
- # @return [Symbol, nil] The method name to lazily resolve `obj`, or nil if `obj`'s class wasn't registered wtih {#lazy_resolve}.
130
+ # @return [Symbol, nil] The method name to lazily resolve `obj`, or nil if `obj`'s class wasn't registered with {#lazy_resolve}.
131
131
  def lazy_method_name(obj)
132
132
  lazy_methods.get(obj)
133
133
  end
@@ -1075,6 +1075,7 @@ module GraphQL
1075
1075
  raise GraphQL::Error, "Second definition of `subscription(...)` (#{new_subscription_object.inspect}) is invalid, already configured with #{@subscription_object.inspect}"
1076
1076
  else
1077
1077
  @subscription_object = new_subscription_object
1078
+ add_subscription_extension_if_necessary
1078
1079
  add_type_and_traverse(new_subscription_object, root: true)
1079
1080
  nil
1080
1081
  end
@@ -1533,9 +1534,9 @@ module GraphQL
1533
1534
 
1534
1535
  # Add several directives at once
1535
1536
  # @param new_directives [Class]
1536
- def directives(new_directives = nil)
1537
- if new_directives
1538
- new_directives.each { |d| directive(d) }
1537
+ def directives(*new_directives)
1538
+ if new_directives.any?
1539
+ new_directives.flatten.each { |d| directive(d) }
1539
1540
  end
1540
1541
 
1541
1542
  find_inherited_value(:directives, default_directives).merge(own_directives)
@@ -1549,11 +1550,11 @@ module GraphQL
1549
1550
  end
1550
1551
 
1551
1552
  def default_directives
1552
- {
1553
+ @default_directives ||= {
1553
1554
  "include" => GraphQL::Schema::Directive::Include,
1554
1555
  "skip" => GraphQL::Schema::Directive::Skip,
1555
1556
  "deprecated" => GraphQL::Schema::Directive::Deprecated,
1556
- }
1557
+ }.freeze
1557
1558
  end
1558
1559
 
1559
1560
  def tracer(new_tracer)
@@ -1648,6 +1649,20 @@ module GraphQL
1648
1649
  end
1649
1650
  end
1650
1651
 
1652
+ # @api private
1653
+ def add_subscription_extension_if_necessary
1654
+ if interpreter? && !defined?(@subscription_extension_added) && subscription && self.subscriptions
1655
+ @subscription_extension_added = true
1656
+ if subscription.singleton_class.ancestors.include?(Subscriptions::SubscriptionRoot)
1657
+ warn("`extend Subscriptions::SubscriptionRoot` is no longer required; you may remove it from #{self}'s `subscription` root type (#{subscription}).")
1658
+ else
1659
+ subscription.fields.each do |name, field|
1660
+ field.extension(Subscriptions::DefaultSubscriptionResolveExtension)
1661
+ end
1662
+ end
1663
+ end
1664
+ end
1665
+
1651
1666
  private
1652
1667
 
1653
1668
  def lazy_methods
@@ -1768,16 +1783,7 @@ module GraphQL
1768
1783
  if owner.kind.union?
1769
1784
  # It's a union with possible_types
1770
1785
  # Replace the item by class name
1771
- owner.type_memberships.each { |tm|
1772
- possible_type = tm.object_type
1773
- if possible_type.is_a?(String) && (possible_type == type.name)
1774
- # This is a match of Ruby class names, not graphql names,
1775
- # since strings are used to refer to constants.
1776
- tm.object_type = type
1777
- elsif possible_type.is_a?(LateBoundType) && possible_type.graphql_name == type.graphql_name
1778
- tm.object_type = type
1779
- end
1780
- }
1786
+ owner.assign_type_membership_object_type(type)
1781
1787
  own_possible_types[owner.graphql_name] = owner.possible_types
1782
1788
  elsif type.kind.interface? && owner.kind.object?
1783
1789
  new_interfaces = []
@@ -43,9 +43,7 @@ module GraphQL
43
43
  when GraphQL::Language::Nodes::EnumTypeDefinition
44
44
  types[definition.name] = build_enum_type(definition, type_resolver)
45
45
  when GraphQL::Language::Nodes::ObjectTypeDefinition
46
- is_subscription_root = (definition.name == "Subscription" && (schema_definition.nil? || schema_definition.subscription.nil?)) || (schema_definition && (definition.name == schema_definition.subscription))
47
- should_extend_subscription_root = is_subscription_root && interpreter
48
- types[definition.name] = build_object_type(definition, type_resolver, default_resolve: default_resolve, extend_subscription_root: should_extend_subscription_root)
46
+ types[definition.name] = build_object_type(definition, type_resolver, default_resolve: default_resolve)
49
47
  when GraphQL::Language::Nodes::InterfaceTypeDefinition
50
48
  types[definition.name] = build_interface_type(definition, type_resolver)
51
49
  when GraphQL::Language::Nodes::UnionTypeDefinition
@@ -204,7 +202,7 @@ module GraphQL
204
202
  end
205
203
  end
206
204
 
207
- def build_object_type(object_type_definition, type_resolver, default_resolve:, extend_subscription_root:)
205
+ def build_object_type(object_type_definition, type_resolver, default_resolve:)
208
206
  builder = self
209
207
  type_def = nil
210
208
  typed_resolve_fn = ->(field, obj, args, ctx) { default_resolve.call(type_def, field, obj, args, ctx) }
@@ -214,10 +212,6 @@ module GraphQL
214
212
  graphql_name(object_type_definition.name)
215
213
  description(object_type_definition.description)
216
214
  ast_node(object_type_definition)
217
- if extend_subscription_root
218
- # This has to come before `field ...` configurations since it modifies them
219
- extend Subscriptions::SubscriptionRoot
220
- end
221
215
 
222
216
  object_type_definition.interfaces.each do |interface_name|
223
217
  interface_defn = type_resolver.call(interface_name)
@@ -303,7 +297,7 @@ module GraphQL
303
297
 
304
298
  field_definitions.map do |field_definition|
305
299
  type_name = resolve_type_name(field_definition.type)
306
-
300
+ resolve_method_name = "resolve_field_#{field_definition.name}"
307
301
  owner.field(
308
302
  field_definition.name,
309
303
  description: field_definition.description,
@@ -315,14 +309,15 @@ module GraphQL
315
309
  ast_node: field_definition,
316
310
  method_conflict_warning: false,
317
311
  camelize: false,
312
+ resolver_method: resolve_method_name,
318
313
  ) do
319
314
  builder.build_arguments(self, field_definition.arguments, type_resolver)
320
315
 
321
316
  # Don't do this for interfaces
322
317
  if default_resolve
323
- # TODO fragile hack. formalize this API?
324
- define_singleton_method :resolve_field_method do |obj, args, ctx|
325
- default_resolve.call(self, obj.object, args, ctx)
318
+ owner.send(:define_method, resolve_method_name) do |**args|
319
+ field_instance = self.class.get_field(field_definition.name)
320
+ default_resolve.call(field_instance, object, args, context)
326
321
  end
327
322
  end
328
323
  end