module AutoGraphQL::TypeBuilder

Public Instance Methods

build(models_and_opts) click to toggle source
# File lib/autographql/type_builder.rb, line 14
def build models_and_opts
  # first build all objects
  type_map = {}

  models_and_opts.each do |model, opts|
    type_map[model] = build_type model, opts
  end

  models_and_opts.each do |model, opts|
    build_type_methods type_map[model], opts[:methods], type_map
  end

  # build relationships between objects
  type_map.each do |model, type|
    relate type, models_and_opts[model][:fields], type_map
  end

  type_map
end

Private Instance Methods

build_type(model, opts) click to toggle source
# File lib/autographql/type_builder.rb, line 37
def build_type model, opts
  column_types = Hash[model.columns_hash.map do |name, column|
    next nil unless opts[:fields].include? name.to_sym

    type = convert_type(column.type)
    unless type
      raise TypeError.new(
        "unsupported type: '#{column.type}' for #{model.name}::#{column.name}"
      )
    end

    [ name.to_sym, type ]
  end.compact]

  # create type
  GraphQL::ObjectType.define do
    name opts[:name]
    description opts[:description]

    opts[:fields].each do |f|
      # skip relationships
      next unless column_types[f]

      field f, column_types[f]
    end
  end
end
build_type_methods(gql_type, methods, type_map) click to toggle source
# File lib/autographql/type_builder.rb, line 66
def build_type_methods gql_type, methods, type_map
  methods.each do |name, type|
    name = name.to_s

    if type.is_a? Array
      list_type = true
      unless type.length == 1
        raise ArgumentError, "invalid type: #{type}"
      end

      type = type.first
    else
      list_type = false
    end

    type = if type_map.include? type
      type_map[type]
    else
      convert_type type
    end

    if list_type
      type = type.to_list_type
    end

    field = GraphQL::Field.define do
      name name
      type type
    end

    gql_type.fields[name] = field
  end
end
convert_type(type) click to toggle source

convert Active Record type to GraphQL type

# File lib/autographql/type_builder.rb, line 130
def convert_type type
  return type if type.is_a? GraphQL::BaseType

  unless type.is_a? Symbol
    type = type.to_s.downcase.to_sym
  end

  {
    boolean: GraphQL::BOOLEAN_TYPE,
    date: GraphQL::Types::DATE,
    datetime: GraphQL::Types::ISO8601DateTime,
    decimal: GraphQL::Types::DECIMAL,
    float: GraphQL::FLOAT_TYPE,
    int: GraphQL::INT_TYPE,
    integer: GraphQL::INT_TYPE,
    json: GraphQL::Types::JSON,
    string: GraphQL::STRING_TYPE,
    text: GraphQL::STRING_TYPE,
  }[type]
end
relate(type, fields, type_map) click to toggle source
# File lib/autographql/type_builder.rb, line 101
def relate type, fields, type_map
  model = type_map.key type

  belongs_to = model.reflect_on_all_associations(:belongs_to)
  has_one = model.reflect_on_all_associations(:has_one)
  has_many = model.reflect_on_all_associations(:has_many)

  (belongs_to + has_one + has_many).each do |field|
    next unless fields.include? field.name.to_sym
    next unless type_map[field.klass]

    field_type = type_map[field.klass]
    if has_many.include? field
      # make into a list
      field_type = field_type.to_list_type.to_non_null_type
    end

    # create relationship field
    gql_field = GraphQL::Field.define do
      name field.name.to_s
      type field_type
    end

    type.fields[field.name.to_s] = gql_field
  end
end