graphql 1.11.4 → 1.11.5

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