module GraphQL::Client::Schema::ObjectType

def self.new(type, fields = {})

def self.new(type, fields = {})
  Class.new(ObjectClass) do
    extend BaseType
    extend ObjectType
    define_singleton_method(:type) { type }
    define_singleton_method(:fields) { fields }
    const_set(:READERS, {})
    const_set(:PREDICATES, {})
  end
end

def cast(value, errors)

def cast(value, errors)
  case value
  when Hash
    new(value, errors)
  when NilClass
    nil
  else
    raise InvariantError, "expected value to be a Hash, but was #{value.class}"
  end
end

def define_class(definition, ast_nodes)

def define_class(definition, ast_nodes)
  # First, gather all the ast nodes representing a certain selection, by name.
  # We gather AST nodes into arrays so that multiple selections can be grouped, for example:
  #
  #   {
  #     f1 { a b }
  #     f1 { b c }
  #   }
  #
  # should be treated like `f1 { a b c }`
  field_nodes = {}
  ast_nodes.each do |ast_node|
    ast_node.selections.each do |selected_ast_node|
      gather_selections(field_nodes, definition, selected_ast_node)
    end
  end
  # After gathering all the nodes by name, prepare to create methods and classes for them.
  field_classes = {}
  field_nodes.each do |result_name, field_ast_nodes|
    # `result_name` might be an alias, so make sure to get the proper name
    field_name = field_ast_nodes.first.name
    field_definition = definition.client.schema.get_field(type.graphql_name, field_name)
    field_return_type = field_definition.type
    field_classes[result_name.to_sym] = schema_module.define_class(definition, field_ast_nodes, field_return_type)
  end
  spreads = definition.indexes[:spreads][ast_nodes.first]
  WithDefinition.new(self, field_classes, definition, spreads)
end

def define_field(name, type)

def define_field(name, type)
  name = name.to_s
  method_name = ActiveSupport::Inflector.underscore(name)
  define_method(method_name) do
    @casted_data.fetch(name) do
      @casted_data[name] = type.cast(@data[name], @errors.filter_by_path(name))
    end
  end
  define_method("#{method_name}?") do
    @data[name] ? true : false
  end
end

def gather_selections(fields, definition, selected_ast_node)

If it's a fragment, continue recursively checking the selections on the fragment.
Given an AST selection on this object, gather it into `fields` if it applies.
def gather_selections(fields, definition, selected_ast_node)
  case selected_ast_node
  when GraphQL::Language::Nodes::InlineFragment
    continue_selection = if selected_ast_node.type.nil?
                           true
                         else
                           type_condition = definition.client.get_type(selected_ast_node.type.name)
                           applicable_types = definition.client.possible_types(type_condition)
                           # continue if this object type is one of the types matching the fragment condition
                           applicable_types.include?(type)
                         end
    if continue_selection
      selected_ast_node.selections.each do |next_selected_ast_node|
        gather_selections(fields, definition, next_selected_ast_node)
      end
    end
  when GraphQL::Language::Nodes::FragmentSpread
    fragment_definition = definition.document.definitions.find do |defn|
      defn.is_a?(GraphQL::Language::Nodes::FragmentDefinition) && defn.name == selected_ast_node.name
    end
    type_condition = definition.client.get_type(fragment_definition.type.name)
    applicable_types = definition.client.possible_types(type_condition)
    # continue if this object type is one of the types matching the fragment condition
    continue_selection = applicable_types.include?(type)
    if continue_selection
      fragment_definition.selections.each do |next_selected_ast_node|
        gather_selections(fields, definition, next_selected_ast_node)
      end
    end
  when GraphQL::Language::Nodes::Field
    operation_definition_for_field = definition.indexes[:definitions][selected_ast_node]
    # Ignore fields defined in other documents.
    if definition.source_document.definitions.include?(operation_definition_for_field)
      field_method_name = selected_ast_node.alias || selected_ast_node.name
      ast_nodes = fields[field_method_name] ||= []
      ast_nodes << selected_ast_node
    end
  else
    raise "Unexpected selection node: #{selected_ast_node}"
  end
end