graphql 1.11.4 → 1.11.5

Sign up to get free protection for your applications and to get access to all the features.
Files changed (44) hide show
  1. checksums.yaml +4 -4
  2. data/lib/generators/graphql/templates/union.erb +1 -1
  3. data/lib/graphql.rb +16 -0
  4. data/lib/graphql/argument.rb +3 -3
  5. data/lib/graphql/backtrace/tracer.rb +2 -1
  6. data/lib/graphql/execution/interpreter.rb +10 -0
  7. data/lib/graphql/execution/interpreter/arguments.rb +1 -1
  8. data/lib/graphql/execution/interpreter/runtime.rb +32 -18
  9. data/lib/graphql/introspection.rb +96 -0
  10. data/lib/graphql/introspection/field_type.rb +7 -3
  11. data/lib/graphql/introspection/input_value_type.rb +6 -0
  12. data/lib/graphql/introspection/introspection_query.rb +6 -92
  13. data/lib/graphql/introspection/type_type.rb +7 -3
  14. data/lib/graphql/language/block_string.rb +24 -5
  15. data/lib/graphql/language/lexer.rb +7 -3
  16. data/lib/graphql/language/lexer.rl +7 -3
  17. data/lib/graphql/language/nodes.rb +1 -1
  18. data/lib/graphql/language/parser.rb +107 -103
  19. data/lib/graphql/language/parser.y +4 -0
  20. data/lib/graphql/language/sanitized_printer.rb +59 -26
  21. data/lib/graphql/name_validator.rb +6 -7
  22. data/lib/graphql/pagination/connections.rb +2 -0
  23. data/lib/graphql/query.rb +2 -2
  24. data/lib/graphql/query/context.rb +10 -2
  25. data/lib/graphql/schema.rb +30 -16
  26. data/lib/graphql/schema/argument.rb +56 -5
  27. data/lib/graphql/schema/build_from_definition.rb +60 -35
  28. data/lib/graphql/schema/directive/deprecated.rb +1 -1
  29. data/lib/graphql/schema/field.rb +10 -4
  30. data/lib/graphql/schema/input_object.rb +5 -3
  31. data/lib/graphql/schema/interface.rb +1 -1
  32. data/lib/graphql/schema/late_bound_type.rb +2 -2
  33. data/lib/graphql/schema/loader.rb +1 -0
  34. data/lib/graphql/schema/member/build_type.rb +14 -4
  35. data/lib/graphql/schema/member/has_arguments.rb +3 -1
  36. data/lib/graphql/schema/member/type_system_helpers.rb +2 -2
  37. data/lib/graphql/schema/relay_classic_mutation.rb +3 -1
  38. data/lib/graphql/schema/timeout.rb +29 -15
  39. data/lib/graphql/schema/validation.rb +8 -0
  40. data/lib/graphql/static_validation/validator.rb +7 -4
  41. data/lib/graphql/subscriptions.rb +1 -3
  42. data/lib/graphql/subscriptions/action_cable_subscriptions.rb +21 -7
  43. data/lib/graphql/version.rb +1 -1
  44. metadata +2 -2
@@ -466,6 +466,10 @@ def self.parse(query_string, filename: nil, tracer: GraphQL::Tracing::NullTracer
466
466
  self.new(query_string, filename: filename, tracer: tracer).parse_document
467
467
  end
468
468
 
469
+ def self.parse_file(filename, tracer: GraphQL::Tracing::NullTracer)
470
+ self.parse(File.read(filename), filename: filename, tracer: tracer)
471
+ end
472
+
469
473
  private
470
474
 
471
475
  def next_token
@@ -19,11 +19,12 @@ module GraphQL
19
19
 
20
20
  REDACTED = "\"<REDACTED>\""
21
21
 
22
- def initialize(query)
22
+ def initialize(query, inline_variables: true)
23
23
  @query = query
24
24
  @current_type = nil
25
25
  @current_field = nil
26
26
  @current_input_type = nil
27
+ @inline_variables = inline_variables
27
28
  end
28
29
 
29
30
  # @return [String, nil] A scrubbed query string, if the query was valid.
@@ -36,15 +37,14 @@ module GraphQL
36
37
  end
37
38
 
38
39
  def print_node(node, indent: "")
39
- if node.is_a?(String)
40
- type = @current_input_type.unwrap
41
- # Replace any strings that aren't IDs or Enum values with REDACTED
42
- if type.kind.enum? || type.graphql_name == "ID"
43
- super
40
+ case node
41
+ when FalseClass, Float, Integer, String, TrueClass
42
+ if @current_argument && redact_argument_value?(@current_argument, node)
43
+ redacted_argument_value(@current_argument)
44
44
  else
45
- REDACTED
45
+ super
46
46
  end
47
- elsif node.is_a?(Array)
47
+ when Array
48
48
  old_input_type = @current_input_type
49
49
  if @current_input_type && @current_input_type.list?
50
50
  @current_input_type = @current_input_type.of_type
@@ -59,28 +59,57 @@ module GraphQL
59
59
  end
60
60
  end
61
61
 
62
+ # Indicates whether or not to redact non-null values for the given argument. Defaults to redacting all strings
63
+ # arguments but this can be customized by subclasses.
64
+ def redact_argument_value?(argument, value)
65
+ # Default to redacting any strings or custom scalars encoded as strings
66
+ type = argument.type.unwrap
67
+ value.is_a?(String) && type.kind.scalar? && (type.graphql_name == "String" || !type.default_scalar?)
68
+ end
69
+
70
+ # Returns the value to use for redacted versions of the given argument. Defaults to the
71
+ # string "<REDACTED>".
72
+ def redacted_argument_value(argument)
73
+ REDACTED
74
+ end
75
+
62
76
  def print_argument(argument)
77
+ # We won't have type information if we're recursing into a custom scalar
78
+ return super if @current_input_type && @current_input_type.kind.scalar?
79
+
63
80
  arg_owner = @current_input_type || @current_directive || @current_field
64
- arg_def = arg_owner.arguments[argument.name]
81
+ old_current_argument = @current_argument
82
+ @current_argument = arg_owner.arguments[argument.name]
65
83
 
66
84
  old_input_type = @current_input_type
67
- @current_input_type = arg_def.type.non_null? ? arg_def.type.of_type : arg_def.type
68
- res = super
85
+ @current_input_type = @current_argument.type.non_null? ? @current_argument.type.of_type : @current_argument.type
86
+
87
+ argument_value = if coerce_argument_value_to_list?(@current_input_type, argument.value)
88
+ [argument.value]
89
+ else
90
+ argument.value
91
+ end
92
+ res = "#{argument.name}: #{print_node(argument_value)}".dup
93
+
69
94
  @current_input_type = old_input_type
95
+ @current_argument = old_current_argument
70
96
  res
71
97
  end
72
98
 
73
- def print_list_type(list_type)
74
- old_input_type = @current_input_type
75
- @current_input_type = old_input_type.of_type
76
- res = super
77
- @current_input_type = old_input_type
78
- res
99
+ def coerce_argument_value_to_list?(type, value)
100
+ type.list? &&
101
+ !value.is_a?(Array) &&
102
+ !value.nil? &&
103
+ !value.is_a?(GraphQL::Language::Nodes::VariableIdentifier)
79
104
  end
80
105
 
81
106
  def print_variable_identifier(variable_id)
82
- variable_value = query.variables[variable_id.name]
83
- print_node(value_to_ast(variable_value, @current_input_type))
107
+ if @inline_variables
108
+ variable_value = query.variables[variable_id.name]
109
+ print_node(value_to_ast(variable_value, @current_input_type))
110
+ else
111
+ super
112
+ end
84
113
  end
85
114
 
86
115
  def print_field(field, indent: "")
@@ -132,10 +161,14 @@ module GraphQL
132
161
  old_type = @current_type
133
162
  @current_type = query.schema.public_send(operation_definition.operation_type)
134
163
 
135
- out = "#{indent}#{operation_definition.operation_type}".dup
136
- out << " #{operation_definition.name}" if operation_definition.name
137
- out << print_directives(operation_definition.directives)
138
- out << print_selections(operation_definition.selections, indent: indent)
164
+ if @inline_variables
165
+ out = "#{indent}#{operation_definition.operation_type}".dup
166
+ out << " #{operation_definition.name}" if operation_definition.name
167
+ out << print_directives(operation_definition.directives)
168
+ out << print_selections(operation_definition.selections, indent: indent)
169
+ else
170
+ out = super
171
+ end
139
172
 
140
173
  @current_type = old_type
141
174
  out
@@ -171,10 +204,10 @@ module GraphQL
171
204
  arguments: arguments
172
205
  )
173
206
  when "LIST"
174
- if value.respond_to?(:each)
175
- value.each { |v| value_to_ast(v, type.of_type) }
207
+ if value.is_a?(Array)
208
+ value.map { |v| value_to_ast(v, type.of_type) }
176
209
  else
177
- [value].each { |v| value_to_ast(v, type.of_type) }
210
+ [value].map { |v| value_to_ast(v, type.of_type) }
178
211
  end
179
212
  when "ENUM"
180
213
  GraphQL::Language::Nodes::Enum.new(name: value)
@@ -1,16 +1,15 @@
1
1
  # frozen_string_literal: true
2
2
  module GraphQL
3
3
  class NameValidator
4
- VALID_NAME_REGEX = /^[_a-zA-Z][_a-zA-Z0-9]*$/
5
-
6
- def self.validate!(name)
7
- raise GraphQL::InvalidNameError.new(name, VALID_NAME_REGEX) unless valid?(name)
4
+ if !String.method_defined?(:match?)
5
+ using GraphQL::StringMatchBackport
8
6
  end
9
7
 
10
- private
8
+ VALID_NAME_REGEX = /^[_a-zA-Z][_a-zA-Z0-9]*$/
11
9
 
12
- def self.valid?(name)
13
- name =~ VALID_NAME_REGEX
10
+ def self.validate!(name)
11
+ name = name.is_a?(String) ? name : name.to_s
12
+ raise GraphQL::InvalidNameError.new(name, VALID_NAME_REGEX) unless name.match?(VALID_NAME_REGEX)
14
13
  end
15
14
  end
16
15
  end
@@ -66,6 +66,8 @@ module GraphQL
66
66
  # Used by the runtime to wrap values in connection wrappers.
67
67
  # @api Private
68
68
  def wrap(field, parent, items, arguments, context, wrappers: all_wrappers)
69
+ return items if GraphQL::Execution::Interpreter::RawValue === items
70
+
69
71
  impl = nil
70
72
 
71
73
  items.class.ancestors.each { |cls|
@@ -259,9 +259,9 @@ module GraphQL
259
259
  # - Variables inlined to the query
260
260
  # - Strings replaced with `<REDACTED>`
261
261
  # @return [String, nil] Returns nil if the query is invalid.
262
- def sanitized_query_string
262
+ def sanitized_query_string(inline_variables: true)
263
263
  with_prepared_ast {
264
- GraphQL::Language::SanitizedPrinter.new(self).sanitized_query_string
264
+ GraphQL::Language::SanitizedPrinter.new(self, inline_variables: inline_variables).sanitized_query_string
265
265
  }
266
266
  end
267
267
 
@@ -34,7 +34,7 @@ module GraphQL
34
34
  # Remove this child from the result value
35
35
  # (used for null propagation and skip)
36
36
  # @api private
37
- def delete(child_ctx)
37
+ def delete_child(child_ctx)
38
38
  @value.delete(child_ctx.key)
39
39
  end
40
40
 
@@ -179,6 +179,14 @@ module GraphQL
179
179
  @provided_values[key]
180
180
  end
181
181
 
182
+ def delete(key)
183
+ if @scoped_context.key?(key)
184
+ @scoped_context.delete(key)
185
+ else
186
+ @provided_values.delete(key)
187
+ end
188
+ end
189
+
182
190
  UNSPECIFIED_FETCH_DEFAULT = Object.new
183
191
 
184
192
  def fetch(key, default = UNSPECIFIED_FETCH_DEFAULT)
@@ -312,7 +320,7 @@ module GraphQL
312
320
  end
313
321
  when GraphQL::Execution::Execute::SKIP
314
322
  @parent.skipped = true
315
- @parent.delete(self)
323
+ @parent.delete_child(self)
316
324
  else
317
325
  @value = new_value
318
326
  end
@@ -789,20 +789,25 @@ module GraphQL
789
789
  # @param using [Hash] Plugins to attach to the created schema with `use(key, value)`
790
790
  # @param interpreter [Boolean] If false, the legacy {Execution::Execute} runtime will be used
791
791
  # @return [Class] the schema described by `document`
792
- def self.from_definition(definition_or_path, default_resolve: nil, interpreter: true, parser: BuildFromDefinition::DefaultParser, using: {})
792
+ def self.from_definition(definition_or_path, default_resolve: nil, interpreter: true, parser: GraphQL.default_parser, using: {})
793
793
  # If the file ends in `.graphql`, treat it like a filepath
794
- definition = if definition_or_path.end_with?(".graphql")
795
- File.read(definition_or_path)
794
+ if definition_or_path.end_with?(".graphql")
795
+ GraphQL::Schema::BuildFromDefinition.from_definition_path(
796
+ definition_or_path,
797
+ default_resolve: default_resolve,
798
+ parser: parser,
799
+ using: using,
800
+ interpreter: interpreter,
801
+ )
796
802
  else
797
- definition_or_path
798
- end
799
- GraphQL::Schema::BuildFromDefinition.from_definition(
800
- definition,
801
- default_resolve: default_resolve,
802
- parser: parser,
803
- using: using,
804
- interpreter: interpreter,
805
- )
803
+ GraphQL::Schema::BuildFromDefinition.from_definition(
804
+ definition_or_path,
805
+ default_resolve: default_resolve,
806
+ parser: parser,
807
+ using: using,
808
+ interpreter: interpreter,
809
+ )
810
+ end
806
811
  end
807
812
 
808
813
  # Error that is raised when [#Schema#from_definition] is passed an invalid schema definition string.
@@ -832,7 +837,7 @@ module GraphQL
832
837
  # @param except [<#call(member, ctx)>]
833
838
  # @return [Hash] GraphQL result
834
839
  def as_json(only: nil, except: nil, context: {})
835
- execute(Introspection::INTROSPECTION_QUERY, only: only, except: except, context: context).to_h
840
+ execute(Introspection.query(include_deprecated_args: true), only: only, except: except, context: context).to_h
836
841
  end
837
842
 
838
843
  # Returns the JSON response of {Introspection::INTROSPECTION_QUERY}.
@@ -880,7 +885,7 @@ module GraphQL
880
885
  # @param except [<#call(member, ctx)>]
881
886
  # @return [Hash] GraphQL result
882
887
  def as_json(only: nil, except: nil, context: {})
883
- execute(Introspection::INTROSPECTION_QUERY, only: only, except: except, context: context).to_h
888
+ execute(Introspection.query(include_deprecated_args: true), only: only, except: except, context: context).to_h
884
889
  end
885
890
 
886
891
  # Return the GraphQL IDL for the schema
@@ -1112,7 +1117,16 @@ module GraphQL
1112
1117
  if type.kind.union?
1113
1118
  type.possible_types(context: context)
1114
1119
  else
1115
- own_possible_types[type.graphql_name] ||
1120
+ stored_possible_types = own_possible_types[type.graphql_name]
1121
+ visible_possible_types = stored_possible_types.select do |possible_type|
1122
+ next true unless type.kind.interface?
1123
+ next true unless possible_type.kind.object?
1124
+
1125
+ # Use `.graphql_name` comparison to match legacy vs class-based types.
1126
+ # When we don't need to support legacy `.define` types, use `.include?(type)` instead.
1127
+ possible_type.interfaces(context).any? { |interface| interface.graphql_name == type.graphql_name }
1128
+ end if stored_possible_types
1129
+ visible_possible_types ||
1116
1130
  introspection_system.possible_types[type.graphql_name] ||
1117
1131
  (
1118
1132
  superclass.respond_to?(:possible_types) ?
@@ -1664,7 +1678,7 @@ module GraphQL
1664
1678
  end
1665
1679
 
1666
1680
  def query_stack_error(query, err)
1667
- query.analysis_errors.push(GraphQL::AnalysisError.new("This query is too large to execute."))
1681
+ query.context.errors.push(GraphQL::ExecutionError.new("This query is too large to execute."))
1668
1682
  end
1669
1683
 
1670
1684
  private
@@ -45,7 +45,8 @@ module GraphQL
45
45
  # @param camelize [Boolean] if true, the name will be camelized when building the schema
46
46
  # @param from_resolver [Boolean] if true, a Resolver class defined this argument
47
47
  # @param method_access [Boolean] If false, don't build method access on legacy {Query::Arguments} instances.
48
- def initialize(arg_name = nil, type_expr = nil, desc = nil, required:, type: nil, name: nil, loads: nil, description: nil, ast_node: nil, default_value: NO_DEFAULT, as: nil, from_resolver: false, camelize: true, prepare: nil, method_access: true, owner:, &definition_block)
48
+ # @param deprecation_reason [String]
49
+ def initialize(arg_name = nil, type_expr = nil, desc = nil, required:, type: nil, name: nil, loads: nil, description: nil, ast_node: nil, default_value: NO_DEFAULT, as: nil, from_resolver: false, camelize: true, prepare: nil, method_access: true, owner:, deprecation_reason: nil, &definition_block)
49
50
  arg_name ||= name
50
51
  @name = -(camelize ? Member::BuildType.camelize(arg_name.to_s) : arg_name.to_s)
51
52
  @type_expr = type_expr || type
@@ -60,6 +61,7 @@ module GraphQL
60
61
  @ast_node = ast_node
61
62
  @from_resolver = from_resolver
62
63
  @method_access = method_access
64
+ self.deprecation_reason = deprecation_reason
63
65
 
64
66
  if definition_block
65
67
  if definition_block.arity == 1
@@ -89,6 +91,18 @@ module GraphQL
89
91
  end
90
92
  end
91
93
 
94
+ # @return [String] Deprecation reason for this argument
95
+ def deprecation_reason(text = nil)
96
+ if text
97
+ validate_deprecated_or_optional(null: @null, deprecation_reason: text)
98
+ @deprecation_reason = text
99
+ else
100
+ @deprecation_reason
101
+ end
102
+ end
103
+
104
+ alias_method :deprecation_reason=, :deprecation_reason
105
+
92
106
  def visible?(context)
93
107
  true
94
108
  end
@@ -143,15 +157,32 @@ module GraphQL
143
157
  if NO_DEFAULT != @default_value
144
158
  argument.default_value = @default_value
145
159
  end
160
+ if @deprecation_reason
161
+ argument.deprecation_reason = @deprecation_reason
162
+ end
146
163
  argument
147
164
  end
148
165
 
149
- attr_writer :type
166
+ def type=(new_type)
167
+ validate_input_type(new_type)
168
+ # This isn't true for LateBoundTypes, but we can assume those will
169
+ # be updated via this codepath later in schema setup.
170
+ if new_type.respond_to?(:non_null?)
171
+ validate_deprecated_or_optional(null: !new_type.non_null?, deprecation_reason: deprecation_reason)
172
+ end
173
+ @type = new_type
174
+ end
150
175
 
151
176
  def type
152
- @type ||= Member::BuildType.parse_type(@type_expr, null: @null)
153
- rescue StandardError => err
154
- raise ArgumentError, "Couldn't build type for Argument #{@owner.name}.#{name}: #{err.class.name}: #{err.message}", err.backtrace
177
+ @type ||= begin
178
+ parsed_type = begin
179
+ Member::BuildType.parse_type(@type_expr, null: @null)
180
+ rescue StandardError => err
181
+ raise ArgumentError, "Couldn't build type for Argument #{@owner.name}.#{name}: #{err.class.name}: #{err.message}", err.backtrace
182
+ end
183
+ # Use the setter method to get validations
184
+ self.type = parsed_type
185
+ end
155
186
  end
156
187
 
157
188
  def statically_coercible?
@@ -186,6 +217,26 @@ module GraphQL
186
217
  raise "Invalid prepare for #{@owner.name}.name: #{@prepare.inspect}"
187
218
  end
188
219
  end
220
+
221
+ private
222
+
223
+ def validate_input_type(input_type)
224
+ if input_type.is_a?(String) || input_type.is_a?(GraphQL::Schema::LateBoundType)
225
+ # Do nothing; assume this will be validated later
226
+ elsif input_type.kind.non_null? || input_type.kind.list?
227
+ validate_input_type(input_type.unwrap)
228
+ elsif !input_type.kind.input?
229
+ raise ArgumentError, "Invalid input type for #{path}: #{input_type.graphql_name}. Must be scalar, enum, or input object, not #{input_type.kind.name}."
230
+ else
231
+ # It's an input type, we're OK
232
+ end
233
+ end
234
+
235
+ def validate_deprecated_or_optional(null:, deprecation_reason:)
236
+ if deprecation_reason && !null
237
+ raise ArgumentError, "Required arguments cannot be deprecated: #{path}."
238
+ end
239
+ end
189
240
  end
190
241
  end
191
242
  end
@@ -4,17 +4,24 @@ require "graphql/schema/build_from_definition/resolve_map"
4
4
  module GraphQL
5
5
  class Schema
6
6
  module BuildFromDefinition
7
+ if !String.method_defined?(:-@)
8
+ using GraphQL::StringDedupBackport
9
+ end
10
+
7
11
  class << self
8
12
  # @see {Schema.from_definition}
9
- def from_definition(definition_string, default_resolve:, using: {}, relay: false, interpreter: true, parser: DefaultParser)
10
- document = parser.parse(definition_string)
11
- default_resolve ||= {}
12
- Builder.build(document, default_resolve: default_resolve, relay: relay, using: using, interpreter: interpreter)
13
+ def from_definition(definition_string, parser: GraphQL.default_parser, **kwargs)
14
+ from_document(parser.parse(definition_string), **kwargs)
13
15
  end
14
- end
15
16
 
16
- # @api private
17
- DefaultParser = GraphQL::Language::Parser
17
+ def from_definition_path(definition_path, parser: GraphQL.default_parser, **kwargs)
18
+ from_document(parser.parse_file(definition_path), **kwargs)
19
+ end
20
+
21
+ def from_document(document, default_resolve:, using: {}, relay: false, interpreter: true)
22
+ Builder.build(document, default_resolve: default_resolve || {}, relay: relay, using: using, interpreter: interpreter)
23
+ end
24
+ end
18
25
 
19
26
  # @api private
20
27
  module Builder
@@ -43,7 +50,7 @@ module GraphQL
43
50
  when GraphQL::Language::Nodes::EnumTypeDefinition
44
51
  types[definition.name] = build_enum_type(definition, type_resolver)
45
52
  when GraphQL::Language::Nodes::ObjectTypeDefinition
46
- types[definition.name] = build_object_type(definition, type_resolver, default_resolve: default_resolve)
53
+ types[definition.name] = build_object_type(definition, type_resolver)
47
54
  when GraphQL::Language::Nodes::InterfaceTypeDefinition
48
55
  types[definition.name] = build_interface_type(definition, type_resolver)
49
56
  when GraphQL::Language::Nodes::UnionTypeDefinition
@@ -111,11 +118,11 @@ module GraphQL
111
118
  end
112
119
 
113
120
  if default_resolve.respond_to?(:resolve_type)
114
- define_singleton_method(:resolve_type) do |*args|
115
- default_resolve.resolve_type(*args)
121
+ def self.resolve_type(*args)
122
+ self.definition_default_resolve.resolve_type(*args)
116
123
  end
117
124
  else
118
- define_singleton_method(:resolve_type) do |*args|
125
+ def self.resolve_type(*args)
119
126
  NullResolveType.call(*args)
120
127
  end
121
128
  end
@@ -141,6 +148,20 @@ module GraphQL
141
148
 
142
149
  # Empty `orphan_types` -- this will make unreachable types ... unreachable.
143
150
  own_orphan_types.clear
151
+
152
+ class << self
153
+ attr_accessor :definition_default_resolve
154
+ end
155
+
156
+ self.definition_default_resolve = default_resolve
157
+
158
+ def definition_default_resolve
159
+ self.class.definition_default_resolve
160
+ end
161
+
162
+ def self.inherited(child_class)
163
+ child_class.definition_default_resolve = self.definition_default_resolve
164
+ end
144
165
  end
145
166
  end
146
167
 
@@ -182,12 +203,12 @@ module GraphQL
182
203
  ast_node(scalar_type_definition)
183
204
 
184
205
  if default_resolve.respond_to?(:coerce_input)
185
- define_singleton_method(:coerce_input) do |val, ctx|
186
- default_resolve.coerce_input(self, val, ctx)
206
+ def self.coerce_input(val, ctx)
207
+ ctx.schema.definition_default_resolve.coerce_input(self, val, ctx)
187
208
  end
188
209
 
189
- define_singleton_method(:coerce_result) do |val, ctx|
190
- default_resolve.coerce_result(self, val, ctx)
210
+ def self.coerce_result(val, ctx)
211
+ ctx.schema.definition_default_resolve.coerce_result(self, val, ctx)
191
212
  end
192
213
  end
193
214
  end
@@ -202,13 +223,10 @@ module GraphQL
202
223
  end
203
224
  end
204
225
 
205
- def build_object_type(object_type_definition, type_resolver, default_resolve:)
226
+ def build_object_type(object_type_definition, type_resolver)
206
227
  builder = self
207
- type_def = nil
208
- typed_resolve_fn = ->(field, obj, args, ctx) { default_resolve.call(type_def, field, obj, args, ctx) }
209
228
 
210
229
  Class.new(GraphQL::Schema::Object) do
211
- type_def = self
212
230
  graphql_name(object_type_definition.name)
213
231
  description(object_type_definition.description)
214
232
  ast_node(object_type_definition)
@@ -218,7 +236,7 @@ module GraphQL
218
236
  implements(interface_defn)
219
237
  end
220
238
 
221
- builder.build_fields(self, object_type_definition.fields, type_resolver, default_resolve: typed_resolve_fn)
239
+ builder.build_fields(self, object_type_definition.fields, type_resolver, default_resolve: true)
222
240
  end
223
241
  end
224
242
 
@@ -247,13 +265,16 @@ module GraphQL
247
265
  end
248
266
  end
249
267
 
268
+ NO_DEFAULT_VALUE = {}.freeze
269
+
250
270
  def build_arguments(type_class, arguments, type_resolver)
251
271
  builder = self
252
272
 
253
273
  arguments.each do |argument_defn|
254
- default_value_kwargs = {}
255
- if !argument_defn.default_value.nil?
256
- default_value_kwargs[:default_value] = builder.build_default_value(argument_defn.default_value)
274
+ default_value_kwargs = if !argument_defn.default_value.nil?
275
+ { default_value: builder.build_default_value(argument_defn.default_value) }
276
+ else
277
+ NO_DEFAULT_VALUE
257
278
  end
258
279
 
259
280
  type_class.argument(
@@ -261,6 +282,7 @@ module GraphQL
261
282
  type: type_resolver.call(argument_defn.type),
262
283
  required: false,
263
284
  description: argument_defn.description,
285
+ deprecation_reason: builder.build_deprecation_reason(argument_defn.directives),
264
286
  ast_node: argument_defn,
265
287
  camelize: false,
266
288
  method_access: false,
@@ -295,10 +317,10 @@ module GraphQL
295
317
  def build_fields(owner, field_definitions, type_resolver, default_resolve:)
296
318
  builder = self
297
319
 
298
- field_definitions.map do |field_definition|
320
+ field_definitions.each do |field_definition|
299
321
  type_name = resolve_type_name(field_definition.type)
300
- resolve_method_name = "resolve_field_#{field_definition.name}"
301
- owner.field(
322
+ resolve_method_name = -"resolve_field_#{field_definition.name}"
323
+ schema_field_defn = owner.field(
302
324
  field_definition.name,
303
325
  description: field_definition.description,
304
326
  type: type_resolver.call(field_definition.type),
@@ -310,16 +332,19 @@ module GraphQL
310
332
  method_conflict_warning: false,
311
333
  camelize: false,
312
334
  resolver_method: resolve_method_name,
313
- ) do
314
- builder.build_arguments(self, field_definition.arguments, type_resolver)
315
-
316
- # Don't do this for interfaces
317
- if default_resolve
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)
335
+ )
336
+
337
+ builder.build_arguments(schema_field_defn, field_definition.arguments, type_resolver)
338
+
339
+ # Don't do this for interfaces
340
+ if default_resolve
341
+ owner.class_eval <<-RUBY, __FILE__, __LINE__
342
+ # frozen_string_literal: true
343
+ def #{resolve_method_name}(**args)
344
+ field_instance = self.class.get_field("#{field_definition.name}")
345
+ context.schema.definition_default_resolve.call(self.class, field_instance, object, args, context)
321
346
  end
322
- end
347
+ RUBY
323
348
  end
324
349
  end
325
350
  end