class GraphQL::Schema::RelayClassicMutation


@see {GraphQL::Schema::Mutation} for an example, it’s basically the same.
using one GraphQL variable (‘$input`) instead of making a separate variable for each argument.
- using a single `input:` argument makes it easy to post whole JSON objects to the mutation
- `clientMutationId` supports optimistic updates and cache rollbacks on the client
These conventions were first specified by Relay Classic, but they come in handy:
class are added to that input object, which is generated by the mutation.
- The mutation accepts one argument called `input`, `argument`s defined in the mutation
- The returned object type always has a field called `clientMutationId` to support that.
client libraries to manage optimistic updates.)
to the resolve method. The value is re-inserted to the response. (It’s for
- An argument called ‘clientMutationId` is always added, but it’s not passed
Mutations that extend this base class get some conventions added for free:

def argument(*args, own_argument: false, **kwargs, &block)

Also apply this argument to the input type:
def argument(*args, own_argument: false, **kwargs, &block)
  it = input_type # make sure any inherited arguments are already added to it
  arg = super(*args, **kwargs, &block)
  # 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

def authorize_arguments(args, values)

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

def default_graphql_name

def default_graphql_name
  "#{self.mutation.graphql_name}Input"
end

def description(new_desc = nil)

def description(new_desc = nil)
  super || "Autogenerated input type of #{self.mutation.graphql_name}"
end

def dummy

def dummy
  @dummy ||= begin
    d = Class.new(GraphQL::Schema::Resolver)
    d.argument_class(self.argument_class)
    # TODO make this lazier?
    d.argument(:input, input_type, description: "Parameters for #{self.graphql_name}")
    d
  end
end

def field_arguments(context = GraphQL::Query::NullContext)

def field_arguments(context = GraphQL::Query::NullContext)
  dummy.arguments(context)
end

def generate_input_type

Returns:
  • (Class) - a subclass of {.input_object_class}
def generate_input_type
  mutation_args = all_argument_definitions
  mutation_class = self
  Class.new(input_object_class) do
    class << self
      def default_graphql_name
        "#{self.mutation.graphql_name}Input"
      end
      def description(new_desc = nil)
        super || "Autogenerated input type of #{self.mutation.graphql_name}"
      end
    end
    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

def get_field_argument(name, context = GraphQL::Query::NullContext)

def get_field_argument(name, context = GraphQL::Query::NullContext)
  dummy.get_argument(name, context)
end

def input_object_class(new_class = nil)

Returns:
  • (Class) - The base class for this mutation's generated input object (default is {GraphQL::Schema::InputObject})

Parameters:
  • new_class (Class) -- The base class to use for generating input object definitions
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

def input_type(new_input_type = nil)

Returns:
  • (Class) - The generated {Schema::InputObject} class for this mutation's `input`

Parameters:
  • new_input_type (Class, nil) -- If provided, it configures this mutation to accept `new_input_type` instead of generating an input type
def input_type(new_input_type = nil)
  if new_input_type
    @input_type = new_input_type
  end
  @input_type ||= generate_input_type
end

def own_field_arguments

def own_field_arguments
  dummy.own_arguments
end

def resolve_with_support(**inputs)

delete `client_mutation_id` from the kwargs.
Override {GraphQL::Schema::Resolver#resolve_with_support} to
def resolve_with_support(**inputs)
  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
  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
  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
end