class GraphQL::Schema::Finder


MySchema.find(“@include”)
@example Finding directives
MySchema.find(“SomeObjectType.myField.anArgument”)
@example Finding arguments
MySchema.find(“SomeObjectType.myField”)
@example Finding fields
MySchema.find(“SomeObjectType”)
@example Finding object types
Find schema members using string paths

def find(path)

def find(path)
  path = path.split(".")
  type_or_directive = path.shift
  if type_or_directive.start_with?("@")
    directive = schema.directives[type_or_directive[1..-1]]
    if directive.nil?
      raise MemberNotFoundError, "Could not find directive `#{type_or_directive}` in schema."
    end
    return directive if path.empty?
    find_in_directive(directive, path: path)
  else
    type = schema.get_type(type_or_directive)
    if type.nil?
      raise MemberNotFoundError, "Could not find type `#{type_or_directive}` in schema."
    end
    return type if path.empty?
    find_in_type(type, path: path)
  end
end

def find_in_directive(directive, path:)

def find_in_directive(directive, path:)
  argument_name = path.shift
  argument = directive.arguments[argument_name]
  if argument.nil?
    raise MemberNotFoundError, "Could not find argument `#{argument_name}` on directive #{directive}."
  end
  argument
end

def find_in_enum_type(enum_type, path:)

def find_in_enum_type(enum_type, path:)
  value_name = path.shift
  enum_value = enum_type.values[value_name]
  if enum_value.nil?
    raise MemberNotFoundError, "Could not find enum value `#{value_name}` on enum type `#{enum_type.graphql_name}`."
  end
  # Error out if path that was provided is too long
  # i.e Enum.VALUE.wat
  if invalid = path.first
    raise MemberNotFoundError, "Cannot select member `#{invalid}` on an enum value."
  end
  enum_value
end

def find_in_field(field, path:)

def find_in_field(field, path:)
  argument_name = path.shift
  argument = field.arguments[argument_name]
  if argument.nil?
    raise MemberNotFoundError, "Could not find argument `#{argument_name}` on field `#{field.name}`."
  end
  # Error out if path that was provided is too long
  # i.e Type.field.argument.somethingBad
  if invalid = path.first
    raise MemberNotFoundError, "Cannot select member `#{invalid}` on a field."
  end
  argument
end

def find_in_fields_type(type, kind:, path:)

def find_in_fields_type(type, kind:, path:)
  field_name = path.shift
  field = schema.get_field(type, field_name)
  if field.nil?
    raise MemberNotFoundError, "Could not find field `#{field_name}` on #{kind} type `#{type.graphql_name}`."
  end
  return field if path.empty?
  find_in_field(field, path: path)
end

def find_in_input_object(input_object, path:)

def find_in_input_object(input_object, path:)
  field_name = path.shift
  input_field = input_object.arguments[field_name]
  if input_field.nil?
    raise MemberNotFoundError, "Could not find input field `#{field_name}` on input object type `#{input_object.graphql_name}`."
  end
  # Error out if path that was provided is too long
  # i.e InputType.inputField.bad
  if invalid = path.first
    raise MemberNotFoundError, "Cannot select member `#{invalid}` on an input field."
  end
  input_field
end

def find_in_type(type, path:)

def find_in_type(type, path:)
  case type.kind.name
  when "OBJECT"
    find_in_fields_type(type, kind: "object", path: path)
  when "INTERFACE"
    find_in_fields_type(type, kind: "interface", path: path)
  when "INPUT_OBJECT"
    find_in_input_object(type, path: path)
  when "UNION"
    # Error out if path that was provided is too long
    # i.e UnionType.PossibleType.aField
    # Use PossibleType.aField instead.
    if invalid = path.first
      raise MemberNotFoundError, "Cannot select union possible type `#{invalid}`. Select the type directly instead."
    end
  when "ENUM"
    find_in_enum_type(type, path: path)
  else
    raise "Unexpected find_in_type: #{type.inspect} (#{path})"
  end
end

def initialize(schema)

def initialize(schema)
  @schema = schema
end