@@ -29,7 +29,13 @@ class FieldImplementationFailed < GraphQL::Error; end
2929 attr_reader :method_str
3030
3131 # @return [Symbol] The method on the type to look up
32- attr_reader :resolver_method
32+ def resolver_method
33+ if @resolver_class
34+ @resolver_class . resolver_method
35+ else
36+ @resolver_method
37+ end
38+ end
3339
3440 # @return [Class] The thing this field was defined on (type, mutation, resolver)
3541 attr_accessor :owner
@@ -68,7 +74,10 @@ def inspect
6874 attr_reader :trace
6975
7076 # @return [String, nil]
71- attr_accessor :subscription_scope
77+ def subscription_scope
78+ @subscription_scope || ( @resolver_class . respond_to? ( :subscription_scope ) ? @resolver_class . subscription_scope : nil )
79+ end
80+ attr_writer :subscription_scope
7281
7382 # Create a field instance from a list of arguments, keyword arguments, and a block.
7483 #
@@ -82,11 +91,9 @@ def inspect
8291 # @return [GraphQL::Schema:Field] an instance of `self
8392 # @see {.initialize} for other options
8493 def self . from_options ( name = nil , type = nil , desc = nil , resolver : nil , mutation : nil , subscription : nil , **kwargs , &block )
85- if ( parent_config = resolver || mutation || subscription )
86- # Get the parent config, merge in local overrides
87- kwargs = parent_config . field_options . merge ( kwargs )
94+ if ( resolver_class = resolver || mutation || subscription )
8895 # Add a reference to that parent class
89- kwargs [ :resolver_class ] = parent_config
96+ kwargs [ :resolver_class ] = resolver_class
9097 end
9198
9299 if name
@@ -119,7 +126,9 @@ def self.from_options(name = nil, type = nil, desc = nil, resolver: nil, mutatio
119126 def connection?
120127 if @connection . nil?
121128 # Provide default based on type name
122- return_type_name = if @return_type_expr
129+ return_type_name = if @resolver_class && @resolver_class . type
130+ Member ::BuildType . to_type_name ( @resolver_class . type )
131+ elsif @return_type_expr
123132 Member ::BuildType . to_type_name ( @return_type_expr )
124133 else
125134 # As a last ditch, try to force loading the return type:
@@ -192,7 +201,7 @@ def method_conflict_warning?
192201 # @param ast_node [Language::Nodes::FieldDefinition, nil] If this schema was parsed from definition, this AST node defined the field
193202 # @param method_conflict_warning [Boolean] If false, skip the warning if this field's method conflicts with a built-in method
194203 # @param validates [Array<Hash>] Configurations for validating this field
195- def initialize ( type : nil , name : nil , owner : nil , null : true , description : nil , deprecation_reason : nil , method : nil , hash_key : nil , dig : nil , resolver_method : nil , connection : nil , max_page_size : :not_given , scope : nil , introspection : false , camelize : true , trace : nil , complexity : 1 , ast_node : nil , extras : EMPTY_ARRAY , extensions : EMPTY_ARRAY , connection_extension : self . class . connection_extension , resolver_class : nil , subscription_scope : nil , relay_node_field : false , relay_nodes_field : false , method_conflict_warning : true , broadcastable : nil , arguments : EMPTY_HASH , directives : EMPTY_HASH , validates : EMPTY_ARRAY , &definition_block )
204+ def initialize ( type : nil , name : nil , owner : nil , null : true , description : nil , deprecation_reason : nil , method : nil , hash_key : nil , dig : nil , resolver_method : nil , connection : nil , max_page_size : :not_given , scope : nil , introspection : false , camelize : true , trace : nil , complexity : nil , ast_node : nil , extras : EMPTY_ARRAY , extensions : EMPTY_ARRAY , connection_extension : self . class . connection_extension , resolver_class : nil , subscription_scope : nil , relay_node_field : false , relay_nodes_field : false , method_conflict_warning : true , broadcastable : nil , arguments : EMPTY_HASH , directives : EMPTY_HASH , validates : EMPTY_ARRAY , &definition_block )
196205 if name . nil?
197206 raise ArgumentError , "missing first `name` argument or keyword `name:`"
198207 end
@@ -238,7 +247,9 @@ def initialize(type: nil, name: nil, owner: nil, null: true, description: nil, d
238247 @max_page_size = max_page_size == :not_given ? nil : max_page_size
239248 @introspection = introspection
240249 @extras = extras
241- @broadcastable = broadcastable
250+ if !broadcastable . nil?
251+ @broadcastable = broadcastable
252+ end
242253 @resolver_class = resolver_class
243254 @scope = scope
244255 @trace = trace
@@ -282,6 +293,10 @@ def initialize(type: nil, name: nil, owner: nil, null: true, description: nil, d
282293 self . extensions ( extensions )
283294 end
284295
296+ if resolver_class && resolver_class . extensions . any?
297+ self . extensions ( resolver_class . extensions )
298+ end
299+
285300 if directives . any?
286301 directives . each do |( dir_class , options ) |
287302 self . directive ( dir_class , **options )
@@ -306,14 +321,22 @@ def initialize(type: nil, name: nil, owner: nil, null: true, description: nil, d
306321 # @return [Boolean, nil]
307322 # @see GraphQL::Subscriptions::BroadcastAnalyzer
308323 def broadcastable?
309- @broadcastable
324+ if defined? ( @broadcastable )
325+ @broadcastable
326+ elsif @resolver_class
327+ @resolver_class . broadcastable?
328+ else
329+ nil
330+ end
310331 end
311332
312333 # @param text [String]
313334 # @return [String]
314335 def description ( text = nil )
315336 if text
316337 @description = text
338+ elsif @resolver_class
339+ @description || @resolver_class . description
317340 else
318341 @description
319342 end
@@ -379,7 +402,12 @@ def extension(extension_class, options = nil)
379402 def extras ( new_extras = nil )
380403 if new_extras . nil?
381404 # Read the value
382- @extras
405+ field_extras = @extras
406+ if @resolver_class && @resolver_class . extras . any?
407+ field_extras + @resolver_class . extras
408+ else
409+ field_extras
410+ end
383411 else
384412 if @extras . frozen?
385413 @extras = @extras . dup
@@ -462,33 +490,43 @@ def complexity(new_complexity = nil)
462490 when Numeric
463491 @complexity = new_complexity
464492 when nil
465- @complexity
493+ if @resolver_class
494+ @complexity || @resolver_class . complexity || 1
495+ else
496+ @complexity || 1
497+ end
466498 else
467499 raise ( "Invalid complexity: #{ new_complexity . inspect } on #{ @name } " )
468500 end
469501 end
470502
471503 # @return [Boolean] True if this field's {#max_page_size} should override the schema default.
472504 def has_max_page_size?
473- @has_max_page_size
505+ @has_max_page_size || ( @resolver_class && @resolver_class . has_max_page_size? )
474506 end
475507
476508 # @return [Integer, nil] Applied to connections if {#has_max_page_size?}
477- attr_reader :max_page_size
509+ def max_page_size
510+ @max_page_size || ( @resolver_class && @resolver_class . max_page_size )
511+ end
478512
479513 class MissingReturnTypeError < GraphQL ::Error ; end
480514 attr_writer :type
481515
482516 def type
483- @type ||= if @return_type_expr . nil?
484- # Not enough info to determine type
485- message = "Can't determine the return type for #{ self . path } "
486- if @resolver_class
487- message += " (it has `resolver: #{ @resolver_class } `, perhaps that class is missing a `type ...` declaration, or perhaps its type causes a cyclical loading issue)"
488- end
489- raise MissingReturnTypeError , message
517+ if @resolver_class && ( t = @resolver_class . type )
518+ t
490519 else
491- Member ::BuildType . parse_type ( @return_type_expr , null : @return_type_null )
520+ @type ||= if @return_type_expr . nil?
521+ # Not enough info to determine type
522+ message = "Can't determine the return type for #{ self . path } "
523+ if @resolver_class
524+ message += " (it has `resolver: #{ @resolver_class } `, perhaps that class is missing a `type ...` declaration, or perhaps its type causes a cyclical loading issue)"
525+ end
526+ raise MissingReturnTypeError , message
527+ else
528+ Member ::BuildType . parse_type ( @return_type_expr , null : @return_type_null )
529+ end
492530 end
493531 rescue GraphQL ::Schema ::InvalidDocumentError , MissingReturnTypeError => err
494532 # Let this propagate up
@@ -618,14 +656,14 @@ def public_send_field(unextended_obj, unextended_ruby_kwargs, query_ctx)
618656 # - A method on the wrapped object;
619657 # - Or, raise not implemented.
620658 #
621- if obj . respond_to? ( @ resolver_method)
622- method_to_call = @ resolver_method
659+ if obj . respond_to? ( resolver_method )
660+ method_to_call = resolver_method
623661 method_receiver = obj
624662 # Call the method with kwargs, if there are any
625663 if ruby_kwargs . any?
626- obj . public_send ( @ resolver_method, **ruby_kwargs )
664+ obj . public_send ( resolver_method , **ruby_kwargs )
627665 else
628- obj . public_send ( @ resolver_method)
666+ obj . public_send ( resolver_method )
629667 end
630668 elsif obj . object . is_a? ( Hash )
631669 inner_object = obj . object
@@ -648,7 +686,7 @@ def public_send_field(unextended_obj, unextended_ruby_kwargs, query_ctx)
648686 raise <<-ERR
649687 Failed to implement #{ @owner . graphql_name } .#{ @name } , tried:
650688
651- - `#{ obj . class } ##{@ resolver_method}`, which did not exist
689+ - `#{ obj . class } ##{resolver_method}`, which did not exist
652690 - `#{ obj . object . class } ##{@method_sym}`, which did not exist
653691 - Looking up hash key `#{ @method_sym . inspect } ` or `#{ @method_str . inspect } ` on `#{ obj . object } `, but it wasn't a Hash
654692
0 commit comments