class GraphQL::Schema::FieldExtension

Extend this class to make field-level customizations to resolve behavior.

When a extension is added to a field with ‘extension(MyExtension)`, a `MyExtension` instance is created, and its hooks are applied whenever that field is called.

The instance is frozen so that instance variables aren’t modified during query execution, which could cause all kinds of issues due to race conditions.

Constants

NO_EXTRAS

Attributes

added_default_arguments[R]

@return [Array<Symbol>, nil] ‘default_argument`s added, if any were added (otherwise, `nil`)

added_extras[R]

@api private

field[R]

@return [GraphQL::Schema::Field]

options[R]

@return [Object]

Public Class Methods

default_argument(*argument_args, **argument_kwargs) click to toggle source

@see Argument#initialize @see HasArguments#argument

# File lib/graphql/schema/field_extension.rb, line 48
def default_argument(*argument_args, **argument_kwargs)
  configs = @own_default_argument_configurations ||= []
  configs << [argument_args, argument_kwargs]
end
default_argument_configurations() click to toggle source

@return [Array(Array, Hash), nil] A list of default argument configs, or ‘nil` if there aren’t any

# File lib/graphql/schema/field_extension.rb, line 34
def default_argument_configurations
  args = superclass.respond_to?(:default_argument_configurations) ? superclass.default_argument_configurations : nil
  if @own_default_argument_configurations
    if args
      args.concat(@own_default_argument_configurations)
    else
      args = @own_default_argument_configurations.dup
    end
  end
  args
end
extras(new_extras = nil) click to toggle source

If configured, these ‘extras` will be added to the field if they aren’t already present, but removed by from ‘arguments` before the field’s ‘resolve` is called. (The extras will be present for other extensions, though.)

@param new_extras [Array<Symbol>] If provided, assign extras used by this extension @return [Array<Symbol>] any extras assigned to this extension

# File lib/graphql/schema/field_extension.rb, line 59
def extras(new_extras = nil)
  if new_extras
    @own_extras = new_extras
  end

  inherited_extras = self.superclass.respond_to?(:extras) ? superclass.extras : nil
  if @own_extras
    if inherited_extras
      inherited_extras + @own_extras
    else
      @own_extras
    end
  elsif inherited_extras
    inherited_extras
  else
    NO_EXTRAS
  end
end
new(field:, options:) click to toggle source

Called when the extension is mounted with ‘extension(name, options)`. The instance will be frozen to avoid improper use of state during execution. @param field [GraphQL::Schema::Field] The field where this extension was mounted @param options [Object] The second argument to `extension`, or `{}` if nothing was passed.

# File lib/graphql/schema/field_extension.rb, line 25
def initialize(field:, options:)
  @field = field
  @options = options || {}
  @added_default_arguments = nil
  apply
end

Public Instance Methods

after_define() click to toggle source

Called after the field’s definition block has been executed. (Any arguments from the block are present on ‘field`) @return [void]

# File lib/graphql/schema/field_extension.rb, line 91
def after_define
end
after_define_apply() click to toggle source

@api private

# File lib/graphql/schema/field_extension.rb, line 95
def after_define_apply
  after_define
  if (configs = self.class.default_argument_configurations)
    existing_keywords = field.all_argument_definitions.map(&:keyword)
    existing_keywords.uniq!
    @added_default_arguments = []
    configs.each do |config|
      argument_args, argument_kwargs = config
      arg_name = argument_args[0]
      if !existing_keywords.include?(arg_name)
        @added_default_arguments << arg_name
        field.argument(*argument_args, **argument_kwargs)
      end
    end
  end
  if (extras = self.class.extras).any?
    @added_extras = extras - field.extras
    field.extras(@added_extras)
  else
    @added_extras = nil
  end
  freeze
end
after_resolve(object:, arguments:, context:, value:, memo:) click to toggle source

Called after {#field} was resolved, and after any lazy values (like ‘Promise`s) were synced, but before the value was added to the GraphQL response.

Whatever this hook returns will be used as the return value.

@param object [Object] The object the field is being resolved on @param arguments [Hash] Ruby keyword arguments for resolving this field @param context [Query::Context] the context for this query @param value [Object] Whatever the field previously returned @param memo [Object] The third value yielded by {#resolve}, or ‘nil` if there wasn’t one @return [Object] The return value for this field.

# File lib/graphql/schema/field_extension.rb, line 151
def after_resolve(object:, arguments:, context:, value:, memo:)
  value
end
apply() click to toggle source

Called when this extension is attached to a field. The field definition may be extended during this method. @return [void]

# File lib/graphql/schema/field_extension.rb, line 85
def apply
end
resolve(object:, arguments:, context:) { |object, arguments, nil| ... } click to toggle source

Called before resolving {#field}. It should either:

  • ‘yield` values to continue execution; OR

  • return something else to shortcut field execution.

Whatever this method returns will be used for execution.

@param object [Object] The object the field is being resolved on @param arguments [Hash] Ruby keyword arguments for resolving this field @param context [Query::Context] the context for this query @yieldparam object [Object] The object to continue resolving the field on @yieldparam arguments [Hash] The keyword arguments to continue resolving with @yieldparam memo [Object] Any extension-specific value which will be passed to {#after_resolve} later @return [Object] The return value for this field.

# File lib/graphql/schema/field_extension.rb, line 136
def resolve(object:, arguments:, context:)
  yield(object, arguments, nil)
end