graphql 1.10.0.pre1 → 1.10.0.pre2

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 (110) hide show
  1. checksums.yaml +4 -4
  2. data/lib/generators/graphql/core.rb +1 -0
  3. data/lib/generators/graphql/install_generator.rb +1 -0
  4. data/lib/generators/graphql/mutation_generator.rb +1 -1
  5. data/lib/generators/graphql/templates/base_field.erb +0 -4
  6. data/lib/generators/graphql/templates/base_mutation.erb +8 -0
  7. data/lib/generators/graphql/templates/graphql_controller.erb +5 -0
  8. data/lib/generators/graphql/templates/mutation.erb +1 -1
  9. data/lib/generators/graphql/templates/schema.erb +1 -1
  10. data/lib/graphql.rb +4 -1
  11. data/lib/graphql/analysis/ast.rb +14 -13
  12. data/lib/graphql/analysis/ast/analyzer.rb +23 -4
  13. data/lib/graphql/analysis/ast/field_usage.rb +1 -1
  14. data/lib/graphql/analysis/ast/max_query_complexity.rb +3 -3
  15. data/lib/graphql/analysis/ast/max_query_depth.rb +7 -3
  16. data/lib/graphql/analysis/ast/query_complexity.rb +2 -2
  17. data/lib/graphql/analysis/ast/visitor.rb +3 -3
  18. data/lib/graphql/base_type.rb +1 -1
  19. data/lib/graphql/directive.rb +0 -1
  20. data/lib/graphql/directive/deprecated_directive.rb +1 -12
  21. data/lib/graphql/execution/errors.rb +4 -8
  22. data/lib/graphql/execution/interpreter.rb +5 -11
  23. data/lib/graphql/execution/interpreter/runtime.rb +56 -48
  24. data/lib/graphql/execution/lazy/lazy_method_map.rb +4 -0
  25. data/lib/graphql/execution/lookahead.rb +5 -5
  26. data/lib/graphql/execution/multiplex.rb +10 -0
  27. data/lib/graphql/function.rb +1 -1
  28. data/lib/graphql/input_object_type.rb +3 -2
  29. data/lib/graphql/interface_type.rb +1 -1
  30. data/lib/graphql/introspection/base_object.rb +2 -5
  31. data/lib/graphql/introspection/directive_type.rb +1 -1
  32. data/lib/graphql/introspection/entry_points.rb +6 -6
  33. data/lib/graphql/introspection/schema_type.rb +1 -6
  34. data/lib/graphql/introspection/type_type.rb +5 -5
  35. data/lib/graphql/language.rb +1 -1
  36. data/lib/graphql/language/block_string.rb +2 -2
  37. data/lib/graphql/language/definition_slice.rb +21 -10
  38. data/lib/graphql/language/document_from_schema_definition.rb +42 -42
  39. data/lib/graphql/language/lexer.rb +49 -48
  40. data/lib/graphql/language/lexer.rl +49 -48
  41. data/lib/graphql/language/nodes.rb +11 -8
  42. data/lib/graphql/language/parser.rb +4 -1
  43. data/lib/graphql/language/parser.y +4 -1
  44. data/lib/graphql/language/token.rb +1 -1
  45. data/lib/graphql/pagination/array_connection.rb +0 -1
  46. data/lib/graphql/pagination/connection.rb +31 -10
  47. data/lib/graphql/pagination/connections.rb +7 -2
  48. data/lib/graphql/pagination/relation_connection.rb +1 -7
  49. data/lib/graphql/query.rb +9 -4
  50. data/lib/graphql/query/arguments.rb +8 -1
  51. data/lib/graphql/query/literal_input.rb +2 -1
  52. data/lib/graphql/query/variables.rb +5 -1
  53. data/lib/graphql/relay/base_connection.rb +3 -3
  54. data/lib/graphql/relay/relation_connection.rb +9 -5
  55. data/lib/graphql/schema.rb +699 -153
  56. data/lib/graphql/schema/argument.rb +20 -4
  57. data/lib/graphql/schema/build_from_definition.rb +64 -31
  58. data/lib/graphql/schema/built_in_types.rb +5 -5
  59. data/lib/graphql/schema/directive.rb +16 -1
  60. data/lib/graphql/schema/directive/deprecated.rb +18 -0
  61. data/lib/graphql/schema/directive/feature.rb +1 -1
  62. data/lib/graphql/schema/enum.rb +39 -3
  63. data/lib/graphql/schema/field.rb +39 -9
  64. data/lib/graphql/schema/field/connection_extension.rb +4 -4
  65. data/lib/graphql/schema/find_inherited_value.rb +13 -0
  66. data/lib/graphql/schema/finder.rb +13 -11
  67. data/lib/graphql/schema/input_object.rb +109 -1
  68. data/lib/graphql/schema/interface.rb +8 -7
  69. data/lib/graphql/schema/introspection_system.rb +104 -36
  70. data/lib/graphql/schema/late_bound_type.rb +1 -0
  71. data/lib/graphql/schema/list.rb +26 -0
  72. data/lib/graphql/schema/loader.rb +10 -4
  73. data/lib/graphql/schema/member.rb +3 -0
  74. data/lib/graphql/schema/member/base_dsl_methods.rb +23 -13
  75. data/lib/graphql/schema/member/build_type.rb +1 -1
  76. data/lib/graphql/schema/member/has_arguments.rb +2 -2
  77. data/lib/graphql/schema/member/has_fields.rb +15 -6
  78. data/lib/graphql/schema/member/instrumentation.rb +6 -1
  79. data/lib/graphql/schema/member/type_system_helpers.rb +1 -1
  80. data/lib/graphql/schema/member/validates_input.rb +33 -0
  81. data/lib/graphql/schema/non_null.rb +25 -0
  82. data/lib/graphql/schema/object.rb +14 -1
  83. data/lib/graphql/schema/printer.rb +4 -3
  84. data/lib/graphql/schema/relay_classic_mutation.rb +5 -1
  85. data/lib/graphql/schema/resolver.rb +20 -2
  86. data/lib/graphql/schema/scalar.rb +18 -3
  87. data/lib/graphql/schema/subscription.rb +1 -1
  88. data/lib/graphql/schema/timeout_middleware.rb +3 -2
  89. data/lib/graphql/schema/traversal.rb +1 -1
  90. data/lib/graphql/schema/type_expression.rb +22 -24
  91. data/lib/graphql/schema/validation.rb +17 -1
  92. data/lib/graphql/schema/warden.rb +46 -17
  93. data/lib/graphql/schema/wrapper.rb +1 -1
  94. data/lib/graphql/static_validation/base_visitor.rb +10 -6
  95. data/lib/graphql/static_validation/definition_dependencies.rb +21 -12
  96. data/lib/graphql/static_validation/rules/fields_are_defined_on_type.rb +4 -4
  97. data/lib/graphql/static_validation/rules/fragment_spreads_are_possible.rb +3 -3
  98. data/lib/graphql/static_validation/type_stack.rb +2 -2
  99. data/lib/graphql/static_validation/validator.rb +1 -1
  100. data/lib/graphql/subscriptions.rb +38 -13
  101. data/lib/graphql/subscriptions/event.rb +24 -7
  102. data/lib/graphql/subscriptions/instrumentation.rb +1 -1
  103. data/lib/graphql/subscriptions/subscription_root.rb +0 -1
  104. data/lib/graphql/tracing/active_support_notifications_tracing.rb +10 -10
  105. data/lib/graphql/tracing/platform_tracing.rb +1 -2
  106. data/lib/graphql/tracing/skylight_tracing.rb +1 -0
  107. data/lib/graphql/unresolved_type_error.rb +2 -2
  108. data/lib/graphql/upgrader/member.rb +1 -1
  109. data/lib/graphql/version.rb +1 -1
  110. metadata +5 -2
@@ -31,10 +31,10 @@ module GraphQL
31
31
  elsif value.is_a?(GraphQL::Pagination::Connection)
32
32
  # update the connection with some things that may not have been provided
33
33
  value.context ||= context
34
- value.first ||= arguments[:first]
35
- value.after ||= arguments[:after]
36
- value.last ||= arguments[:last]
37
- value.before ||= arguments[:before]
34
+ value.first_value ||= arguments[:first]
35
+ value.after_value ||= arguments[:after]
36
+ value.last_value ||= arguments[:last]
37
+ value.before_value ||= arguments[:before]
38
38
  value.max_page_size ||= field.max_page_size
39
39
  value
40
40
  elsif context.schema.new_connections?
@@ -1,6 +1,19 @@
1
1
  module GraphQL
2
2
  class Schema
3
3
  module FindInheritedValue
4
+ module EmptyObjects
5
+ EMPTY_HASH = {}.freeze
6
+ EMPTY_ARRAY = [].freeze
7
+ end
8
+
9
+ def self.extended(child_cls)
10
+ child_cls.singleton_class.include(EmptyObjects)
11
+ end
12
+
13
+ def self.included(child_cls)
14
+ child_cls.include(EmptyObjects)
15
+ end
16
+
4
17
  private
5
18
 
6
19
  def find_inherited_value(method_name, default_value = nil)
@@ -38,7 +38,7 @@ module GraphQL
38
38
 
39
39
  find_in_directive(directive, path: path)
40
40
  else
41
- type = schema.types[type_or_directive]
41
+ type = schema.get_type(type_or_directive)
42
42
 
43
43
  if type.nil?
44
44
  raise MemberNotFoundError, "Could not find type `#{type_or_directive}` in schema."
@@ -66,22 +66,24 @@ module GraphQL
66
66
  end
67
67
 
68
68
  def find_in_type(type, path:)
69
- case type
70
- when GraphQL::ObjectType
69
+ case type.kind.name
70
+ when "OBJECT"
71
71
  find_in_fields_type(type, kind: "object", path: path)
72
- when GraphQL::InterfaceType
72
+ when "INTERFACE"
73
73
  find_in_fields_type(type, kind: "interface", path: path)
74
- when GraphQL::InputObjectType
74
+ when "INPUT_OBJECT"
75
75
  find_in_input_object(type, path: path)
76
- when GraphQL::UnionType
76
+ when "UNION"
77
77
  # Error out if path that was provided is too long
78
78
  # i.e UnionType.PossibleType.aField
79
79
  # Use PossibleType.aField instead.
80
80
  if invalid = path.first
81
81
  raise MemberNotFoundError, "Cannot select union possible type `#{invalid}`. Select the type directly instead."
82
82
  end
83
- when GraphQL::EnumType
83
+ when "ENUM"
84
84
  find_in_enum_type(type, path: path)
85
+ else
86
+ raise "Unexpected find_in_type: #{type.inspect} (#{path})"
85
87
  end
86
88
  end
87
89
 
@@ -90,7 +92,7 @@ module GraphQL
90
92
  field = schema.get_field(type, field_name)
91
93
 
92
94
  if field.nil?
93
- raise MemberNotFoundError, "Could not find field `#{field_name}` on #{kind} type `#{type}`."
95
+ raise MemberNotFoundError, "Could not find field `#{field_name}` on #{kind} type `#{type.graphql_name}`."
94
96
  end
95
97
 
96
98
  return field if path.empty?
@@ -117,10 +119,10 @@ module GraphQL
117
119
 
118
120
  def find_in_input_object(input_object, path:)
119
121
  field_name = path.shift
120
- input_field = input_object.input_fields[field_name]
122
+ input_field = input_object.arguments[field_name]
121
123
 
122
124
  if input_field.nil?
123
- raise MemberNotFoundError, "Could not find input field `#{field_name}` on input object type `#{input_object}`."
125
+ raise MemberNotFoundError, "Could not find input field `#{field_name}` on input object type `#{input_object.graphql_name}`."
124
126
  end
125
127
 
126
128
  # Error out if path that was provided is too long
@@ -137,7 +139,7 @@ module GraphQL
137
139
  enum_value = enum_type.values[value_name]
138
140
 
139
141
  if enum_value.nil?
140
- raise MemberNotFoundError, "Could not find enum value `#{value_name}` on enum type `#{enum_type}`."
142
+ raise MemberNotFoundError, "Could not find enum value `#{value_name}` on enum type `#{enum_type.graphql_name}`."
141
143
  end
142
144
 
143
145
  # Error out if path that was provided is too long
@@ -5,6 +5,8 @@ module GraphQL
5
5
  extend GraphQL::Schema::Member::AcceptsDefinition
6
6
  extend Forwardable
7
7
  extend GraphQL::Schema::Member::HasArguments
8
+ extend GraphQL::Schema::Member::ValidatesInput
9
+
8
10
  include GraphQL::Dig
9
11
 
10
12
  def initialize(values = nil, ruby_kwargs: nil, context:, defaults_used:)
@@ -57,6 +59,10 @@ module GraphQL
57
59
  to_h
58
60
  end
59
61
 
62
+ def prepare
63
+ self
64
+ end
65
+
60
66
  def unwrap_value(value)
61
67
  case value
62
68
  when Array
@@ -86,7 +92,7 @@ module GraphQL
86
92
  end
87
93
 
88
94
  def key?(key)
89
- @ruby_style_hash.key?(key) || (@arguments && @arguments.key?(key))
95
+ @ruby_style_hash.key?(key) || (@arguments && @arguments.key?(key)) || false
90
96
  end
91
97
 
92
98
  # A copy of the Ruby-style hash
@@ -127,6 +133,108 @@ module GraphQL
127
133
  def kind
128
134
  GraphQL::TypeKinds::INPUT_OBJECT
129
135
  end
136
+
137
+ # @api private
138
+ INVALID_OBJECT_MESSAGE = "Expected %{object} to be a key-value object responding to `to_h` or `to_unsafe_h`."
139
+
140
+
141
+ def validate_non_null_input(input, ctx)
142
+ result = GraphQL::Query::InputValidationResult.new
143
+
144
+ warden = ctx.warden
145
+
146
+ if input.is_a?(Array)
147
+ result.add_problem(INVALID_OBJECT_MESSAGE % { object: JSON.generate(input, quirks_mode: true) })
148
+ return result
149
+ end
150
+
151
+ # We're not actually _using_ the coerced result, we're just
152
+ # using these methods to make sure that the object will
153
+ # behave like a hash below, when we call `each` on it.
154
+ begin
155
+ input.to_h
156
+ rescue
157
+ begin
158
+ # Handle ActionController::Parameters:
159
+ input.to_unsafe_h
160
+ rescue
161
+ # We're not sure it'll act like a hash, so reject it:
162
+ result.add_problem(INVALID_OBJECT_MESSAGE % { object: JSON.generate(input, quirks_mode: true) })
163
+ return result
164
+ end
165
+ end
166
+
167
+ visible_arguments_map = warden.arguments(self).reduce({}) { |m, f| m[f.name] = f; m}
168
+
169
+ # Items in the input that are unexpected
170
+ input.each do |name, value|
171
+ if visible_arguments_map[name].nil?
172
+ result.add_problem("Argument is not defined on #{self.graphql_name}", [name])
173
+ end
174
+ end
175
+
176
+ # Items in the input that are expected, but have invalid values
177
+ visible_arguments_map.map do |name, argument|
178
+ argument_result = argument.type.validate_input(input[name], ctx)
179
+ if !argument_result.valid?
180
+ result.merge_result!(name, argument_result)
181
+ end
182
+ end
183
+
184
+ result
185
+ end
186
+
187
+ def coerce_input(value, ctx)
188
+ input_values = {}
189
+
190
+ arguments.each do |name, argument_defn|
191
+ arg_key = argument_defn.keyword
192
+ has_value = false
193
+ # Accept either string or symbol
194
+ field_value = if value.key?(name)
195
+ has_value = true
196
+ value[name]
197
+ elsif value.key?(arg_key)
198
+ has_value = true
199
+ value[arg_key]
200
+ elsif argument_defn.default_value?
201
+ has_value = true
202
+ argument_defn.default_value
203
+ else
204
+ nil
205
+ end
206
+ # Only continue if some value was found for this argument
207
+ if has_value
208
+ coerced_value = argument_defn.type.coerce_input(field_value, ctx)
209
+ prepared_value = argument_defn.prepare_value(nil, coerced_value, context: ctx)
210
+ input_values[arg_key] = prepared_value
211
+ end
212
+ end
213
+
214
+ input_values
215
+ end
216
+
217
+ # It's funny to think of a _result_ of an input object.
218
+ # This is used for rendering the default value in introspection responses.
219
+ def coerce_result(value, ctx)
220
+ # Allow the application to provide values as :symbols, and convert them to the strings
221
+ value = value.reduce({}) { |memo, (k, v)| memo[k.to_s] = v; memo }
222
+
223
+ result = {}
224
+
225
+ arguments.each do |input_key, input_field_defn|
226
+ input_value = value[input_key]
227
+ if value.key?(input_key)
228
+ result[input_key] = if input_value.nil?
229
+ nil
230
+ else
231
+ input_field_defn.type.coerce_result(input_value, ctx)
232
+ end
233
+ end
234
+ end
235
+
236
+ result
237
+ end
130
238
  end
131
239
  end
132
240
  end
@@ -7,6 +7,7 @@ module GraphQL
7
7
  include GraphQL::Schema::Member::CachedGraphQLDefinition
8
8
  include GraphQL::Relay::TypeExtensions
9
9
  include GraphQL::Schema::Member::BaseDSLMethods
10
+ # ConfigurationExtension's responsibilities are in `def included` below
10
11
  include GraphQL::Schema::Member::TypeSystemHelpers
11
12
  include GraphQL::Schema::Member::HasFields
12
13
  include GraphQL::Schema::Member::HasPath
@@ -21,14 +22,9 @@ module GraphQL
21
22
  self::DefinitionMethods.module_eval(&block)
22
23
  end
23
24
 
24
- # The interface is visible if any of its possible types are visible
25
+ # @see {Schema::Warden} hides interfaces without visible implementations
25
26
  def visible?(context)
26
- context.schema.possible_types(self).each do |type|
27
- if context.schema.visible?(type, context)
28
- return true
29
- end
30
- end
31
- false
27
+ true
32
28
  end
33
29
 
34
30
  # The interface is accessible if any of its possible types are accessible
@@ -64,6 +60,11 @@ module GraphQL
64
60
  child_class.const_set(:DefinitionMethods, defn_methods_module)
65
61
  child_class.extend(child_class::DefinitionMethods)
66
62
  end
63
+ child_class.introspection(introspection)
64
+ child_class.description(description)
65
+ if overridden_graphql_name
66
+ child_class.graphql_name(overridden_graphql_name)
67
+ end
67
68
  elsif child_class < GraphQL::Schema::Object
68
69
  # This is being included into an object type, make sure it's using `implements(...)`
69
70
  backtrace_line = caller(0, 10).find { |line| line.include?("schema/object.rb") && line.include?("in `implements'")}
@@ -2,24 +2,36 @@
2
2
  module GraphQL
3
3
  class Schema
4
4
  class IntrospectionSystem
5
- attr_reader :schema_type, :type_type, :typename_field
5
+ attr_reader :types, :possible_types
6
6
 
7
7
  def initialize(schema)
8
8
  @schema = schema
9
+ @class_based = !!@schema.is_a?(Class)
9
10
  @built_in_namespace = GraphQL::Introspection
10
- @custom_namespace = schema.introspection_namespace || @built_in_namespace
11
-
12
- # Use to-graphql to avoid sharing with any previous instantiations
13
- @schema_type = load_constant(:SchemaType).to_graphql
14
- @type_type = load_constant(:TypeType).to_graphql
15
- @field_type = load_constant(:FieldType).to_graphql
16
- @directive_type = load_constant(:DirectiveType).to_graphql
17
- @enum_value_type = load_constant(:EnumValueType).to_graphql
18
- @input_value_type = load_constant(:InputValueType).to_graphql
19
- @type_kind_enum = load_constant(:TypeKindEnum).to_graphql
20
- @directive_location_enum = load_constant(:DirectiveLocationEnum).to_graphql
11
+ @custom_namespace = if @class_based
12
+ schema.introspection || @built_in_namespace
13
+ else
14
+ schema.introspection_namespace || @built_in_namespace
15
+ end
16
+
17
+ type_defns = [
18
+ load_constant(:SchemaType),
19
+ load_constant(:TypeType),
20
+ load_constant(:FieldType),
21
+ load_constant(:DirectiveType),
22
+ load_constant(:EnumValueType),
23
+ load_constant(:InputValueType),
24
+ load_constant(:TypeKindEnum),
25
+ load_constant(:DirectiveLocationEnum)
26
+ ]
27
+ @types = {}
28
+ @possible_types = {}
29
+ type_defns.each do |t|
30
+ @types[t.graphql_name] = t
31
+ @possible_types[t.graphql_name] = [t]
32
+ end
21
33
  @entry_point_fields =
22
- if schema.disable_introspection_entry_points
34
+ if schema.disable_introspection_entry_points?
23
35
  {}
24
36
  else
25
37
  get_fields_from_class(class_sym: :EntryPoints)
@@ -27,19 +39,6 @@ module GraphQL
27
39
  @dynamic_fields = get_fields_from_class(class_sym: :DynamicFields)
28
40
  end
29
41
 
30
- def object_types
31
- [
32
- @schema_type,
33
- @type_type,
34
- @field_type,
35
- @directive_type,
36
- @enum_value_type,
37
- @input_value_type,
38
- @type_kind_enum,
39
- @directive_location_enum,
40
- ]
41
- end
42
-
43
42
  def entry_points
44
43
  @entry_point_fields.values
45
44
  end
@@ -56,25 +55,94 @@ module GraphQL
56
55
  @dynamic_fields[name]
57
56
  end
58
57
 
58
+ # The introspection system is prepared with a bunch of LateBoundTypes.
59
+ # Replace those with the objects that they refer to, since LateBoundTypes
60
+ # aren't handled at runtime.
61
+ #
62
+ # @api private
63
+ # @return void
64
+ def resolve_late_bindings
65
+ @types.each do |name, t|
66
+ if t.kind.fields?
67
+ t.fields.each do |_name, field_defn|
68
+ field_defn.type = resolve_late_binding(field_defn.type)
69
+ end
70
+ end
71
+ end
72
+
73
+ @entry_point_fields.each do |name, f|
74
+ f.type = resolve_late_binding(f.type)
75
+ end
76
+
77
+ @dynamic_fields.each do |name, f|
78
+ f.type = resolve_late_binding(f.type)
79
+ end
80
+ nil
81
+ end
82
+
59
83
  private
60
84
 
85
+ def resolve_late_binding(late_bound_type)
86
+ case late_bound_type
87
+ when GraphQL::Schema::LateBoundType
88
+ @schema.get_type(late_bound_type.name)
89
+ when GraphQL::Schema::List, GraphQL::ListType
90
+ resolve_late_binding(late_bound_type.of_type).to_list_type
91
+ when GraphQL::Schema::NonNull, GraphQL::NonNullType
92
+ resolve_late_binding(late_bound_type.of_type).to_non_null_type
93
+ when Module
94
+ # It's a normal type -- no change required
95
+ late_bound_type
96
+ else
97
+ raise "Invariant: unexpected type: #{late_bound_type} (#{late_bound_type.class})"
98
+ end
99
+ end
100
+
61
101
  def load_constant(class_name)
62
- @custom_namespace.const_get(class_name)
102
+ const = @custom_namespace.const_get(class_name)
103
+ if @class_based
104
+ dup_type_class(const)
105
+ else
106
+ # Use `.to_graphql` to get a freshly-made version, not shared between schemas
107
+ const.to_graphql
108
+ end
63
109
  rescue NameError
64
110
  # Dup the built-in so that the cached fields aren't shared
65
- @built_in_namespace.const_get(class_name)
111
+ dup_type_class(@built_in_namespace.const_get(class_name))
66
112
  end
67
113
 
68
114
  def get_fields_from_class(class_sym:)
69
- object_class = load_constant(class_sym)
70
- object_type_defn = object_class.to_graphql
71
- extracted_field_defns = {}
72
- object_type_defn.all_fields.each do |field_defn|
73
- inner_resolve = field_defn.resolve_proc
74
- resolve_with_instantiate = PerFieldProxyResolve.new(object_class: object_class, inner_resolve: inner_resolve)
75
- extracted_field_defns[field_defn.name] = field_defn.redefine(resolve: resolve_with_instantiate)
115
+ object_type_defn = load_constant(class_sym)
116
+
117
+ if object_type_defn.is_a?(Module)
118
+ object_type_defn.fields
119
+ else
120
+ extracted_field_defns = {}
121
+ object_class = object_type_defn.metadata[:type_class]
122
+ object_type_defn.all_fields.each do |field_defn|
123
+ inner_resolve = field_defn.resolve_proc
124
+ resolve_with_instantiate = PerFieldProxyResolve.new(object_class: object_class, inner_resolve: inner_resolve)
125
+ extracted_field_defns[field_defn.name] = field_defn.redefine(resolve: resolve_with_instantiate)
126
+ end
127
+ extracted_field_defns
128
+ end
129
+ end
130
+
131
+ # This is probably not 100% robust -- but it has to be good enough to avoid modifying the built-in introspection types
132
+ def dup_type_class(type_class)
133
+ type_name = type_class.graphql_name
134
+ Class.new(type_class) do
135
+ # This won't be inherited like other things will
136
+ graphql_name(type_name)
137
+
138
+ if type_class.kind.fields?
139
+ type_class.fields.each do |_name, field_defn|
140
+ dup_field = field_defn.dup
141
+ dup_field.owner = self
142
+ add_field(dup_field)
143
+ end
144
+ end
76
145
  end
77
- extracted_field_defns
78
146
  end
79
147
 
80
148
  class PerFieldProxyResolve