class GraphQL::Schema::RelayClassicMutation

Mutations that extend this base class get some conventions added for free:

These conventions were first specified by Relay Classic, but they come in handy:

@see {GraphQL::Schema::Mutation} for an example, it's basically the same.

Public Class Methods

argument(*args, **kwargs, &block) click to toggle source

Also apply this argument to the input type:

Calls superclass method GraphQL::Schema::Resolver::argument
# File lib/graphql/schema/relay_classic_mutation.rb, line 86
def argument(*args, **kwargs, &block)
  it = input_type # make sure any inherited arguments are already added to it
  arg = super

  # This definition might be overriding something inherited;
  # if it is, remove the inherited definition so it's not confused at runtime as having multiple definitions
  prev_args = it.own_arguments[arg.graphql_name]
  case prev_args
  when GraphQL::Schema::Argument
    if prev_args.owner != self
      it.own_arguments.delete(arg.graphql_name)
    end
  when Array
    prev_args.reject! { |a| a.owner != self }
    if prev_args.empty?
      it.own_arguments.delete(arg.graphql_name)
    end
  end

  it.add_argument(arg)
  arg
end
field_options() click to toggle source

Extend {Schema::Mutation.field_options} to add the `input` argument

# File lib/graphql/schema/relay_classic_mutation.rb, line 129
def field_options
  sig = super
  # Arguments were added at the root, but they should be nested
  sig[:arguments].clear
  sig[:arguments][:input] = { type: input_type, required: true, description: "Parameters for #{graphql_name}" }
  sig
end
input_object_class(new_class = nil) click to toggle source

The base class for generated input object types @param new_class [Class] The base class to use for generating input object definitions @return [Class] The base class for this mutation's generated input object (default is {GraphQL::Schema::InputObject})

# File lib/graphql/schema/relay_classic_mutation.rb, line 112
def input_object_class(new_class = nil)
  if new_class
    @input_object_class = new_class
  end
  @input_object_class || (superclass.respond_to?(:input_object_class) ? superclass.input_object_class : GraphQL::Schema::InputObject)
end
input_type(new_input_type = nil) click to toggle source

@param new_input_type [Class, nil] If provided, it configures this mutation to accept `new_input_type` instead of generating an input type @return [Class] The generated {Schema::InputObject} class for this mutation's `input`

# File lib/graphql/schema/relay_classic_mutation.rb, line 121
def input_type(new_input_type = nil)
  if new_input_type
    @input_type = new_input_type
  end
  @input_type ||= generate_input_type
end

Private Class Methods

generate_input_type() click to toggle source

Generate the input type for the `input:` argument To customize how input objects are generated, override this method @return [Class] a subclass of {.input_object_class}

# File lib/graphql/schema/relay_classic_mutation.rb, line 142
def generate_input_type
  mutation_args = all_argument_definitions
  mutation_name = graphql_name
  mutation_class = self
  Class.new(input_object_class) do
    graphql_name("#{mutation_name}Input")
    description("Autogenerated input type of #{mutation_name}")
    mutation(mutation_class)
    # these might be inherited:
    mutation_args.each do |arg|
      add_argument(arg)
    end
    argument :client_mutation_id, String, "A unique identifier for the client performing the mutation.", required: false
  end
end

Public Instance Methods

resolve_with_support(**inputs) click to toggle source

Override {GraphQL::Schema::Resolver#resolve_with_support} to delete `client_mutation_id` from the kwargs.

# File lib/graphql/schema/relay_classic_mutation.rb, line 31
def resolve_with_support(**inputs)
  # Without the interpreter, the inputs are unwrapped by an instrumenter.
  # But when using the interpreter, no instrumenters are applied.
  if context.interpreter?
    input = inputs[:input].to_kwargs

    new_extras = field ? field.extras : []
    all_extras = self.class.extras + new_extras

    # Transfer these from the top-level hash to the
    # shortcutted `input:` object
    all_extras.each do |ext|
      # It's possible that the `extra` was not passed along by this point,
      # don't re-add it if it wasn't given here.
      if inputs.key?(ext)
        input[ext] = inputs[ext]
      end
    end
  else
    input = inputs
  end

  if input
    # This is handled by Relay::Mutation::Resolve, a bit hacky, but here we are.
    input_kwargs = input.to_h
    client_mutation_id = input_kwargs.delete(:client_mutation_id)
  else
    # Relay Classic Mutations with no `argument`s
    # don't require `input:`
    input_kwargs = {}
  end

  return_value = if input_kwargs.any?
    super(**input_kwargs)
  else
    super()
  end

  # Again, this is done by an instrumenter when using non-interpreter execution.
  if context.interpreter?
    context.schema.after_lazy(return_value) do |return_hash|
      # It might be an error
      if return_hash.is_a?(Hash)
        return_hash[:client_mutation_id] = client_mutation_id
      end
      return_hash
    end
  else
    return_value
  end
end

Private Instance Methods

authorize_arguments(args, values) click to toggle source
# File lib/graphql/schema/relay_classic_mutation.rb, line 161
def authorize_arguments(args, values)
  # remove the `input` wrapper to match values
  input_args = args["input"].type.unwrap.arguments(context)
  super(input_args, values)
end