fix errors in marker_info and reimplement menu_species, menu_types with Ecto

# This module should only contain the MySQL calls to the backend to
# fetch data. Assembling more complex structures should happen in the
# Assemble modules.
#
# All functions return lists of lists, rather than lists of
# tuples. Main reason is that tuples do not go nicely with JSON.

defmodule GnServer.Data.Store do

  alias GnServer.Backend.MySQL, as: DB
  import Ecto.Query
  alias GnServer.Repo
  alias GnServer.Schema.Species
  alias GnServer.Schema.ProbeSetFreeze
  alias GnServer.Schema.InbredSet
  alias GnServer.Schema.ProbeFreeze
  alias GnServer.Schema.GenoFreeze
  alias GnServer.Schema.PublishFreeze
  alias GnServer.Schema.Tissue
  alias GnServer.Schema.Geno

  defp use_type(id) do
    try do
      { :integer, String.to_integer(id) }
    rescue
      _ in ArgumentError -> { :string, id }
    end
  end

  defp authorize_group(group_name) do
    if group_name != "BXD" do
      raise "Authorization error for " <> group_name
    end
  end

  defp authorize_dataset(dataset_name) do
    {field_name, field_value} =
      case use_type(dataset_name) do
        { :integer, i } -> {:id, i}
        { :string, s }  -> {:Name,s}
      end
#     query = """
# SELECT DISTINCT D.confidentiality,D.public FROM ProbeSetFreeze AS D
# WHERE #{subq}
# """

    query = from x in ProbeSetFreeze,
      select: {x.confidentiality, x.public},
      where: field(x, ^field_name) == ^field_value,
      distinct: true

    rows = Repo.all(query)
    if Enum.count(rows) != 1 do
      raise "Access error"
    end

    [{confidentiality,public}] = rows
    if public == 0 or confidentiality > 0 do
      raise "Authorization error"
    end
  end

  def species do
    query = from s in Species,
      select: {s."SpeciesId", s."Name", s."FullName"}
    Repo.all(query) |> Enum.map(&(Tuple.to_list &1))
  end

  def groups(species) do
    {species_field, species_value} =
      case use_type(species) do
        { :integer, i } -> {:id, i}
        { :string, s }  -> {:Name, s}
      end

    # note this query can be simplified
#     query = """
# SELECT distinct InbredSet.id,InbredSet.Name,InbredSet.FullName
# FROM InbredSet,Species,ProbeFreeze,GenoFreeze,PublishFreeze
# WHERE #{subq}
# and InbredSet.SpeciesId = Species.Id and InbredSet.Name != 'BXD300'
# and (PublishFreeze.InbredSetId = InbredSet.Id
#      or GenoFreeze.InbredSetId = InbredSet.Id
#      or ProbeFreeze.InbredSetId = InbredSet.Id)
# """
    query = from species in Species,
      join: inbredset in InbredSet,
      on: species.id == inbredset."SpeciesId",
      left_join: publishfreeze in PublishFreeze,
      on: publishfreeze."InbredSetId" == inbredset.id,
      left_join: genofreeze in GenoFreeze,
      on: genofreeze."InbredSetId" == inbredset.id,
      left_join: probefreeze in ProbeFreeze,
      on: probefreeze."InbredSetId" == inbredset.id,
      where: field(species, ^species_field) == ^species_value and inbredset."Name" != "BXD300",
      select: {inbredset.id,inbredset."Name",inbredset."FullName"},
      distinct: true

    Repo.all(query) |> Enum.map(&(Tuple.to_list &1))
  end

  def group_info(group) do
    {inbredset_field, inbredset_value} =
      case use_type(group) do
        { :integer, i } -> {:id, i}
        { :string, s }  -> {:Name, s}
      end
#     query = "
# SELECT DISTINCT Species.speciesid,Species.Name,C.InbredSetid,C.name,C.mappingmethodid,C.genetictype
# FROM Species, InbredSet as C
# WHERE #{subq} and C.SpeciesId = Species.Id"
    query = from species in Species,
      join: inbredset in InbredSet,
      on: species.id == inbredset."SpeciesId",
      where: field(inbredset, ^inbredset_field) == ^inbredset_value,
      select: {species."SpeciesId", species."Name", inbredset."InbredSetId", inbredset."Name", inbredset."MappingMethodId", inbredset."GeneticType"},
      distinct: true
    # for r <- rows, do: ( {species_id,species,group_id,group_name,method_id,genetic_type} = r; [group_id,group_name,species_id,species,method_id,genetic_type] )
    Repo.all(query) |> Enum.map(&(Tuple.to_list(&1)))
  end

  def chr_info(dataset_name) do
    subq =
      case use_type(dataset_name) do
        { :integer, i } -> "C.id = #{i}"
        { :string, s }  -> "C.Name = '#{s}'"
      end

      query = """
SELECT Chr_Length.Name, Length
FROM Chr_Length, InbredSet as C
WHERE #{subq}
AND Chr_Length.SpeciesId = C.SpeciesId
ORDER BY Chr_Length.OrderId
      """
    {:ok, rows} = DB.query(query)
    for r <- rows, do: ( {chr_name,chr_len} = r; [chr_name,chr_len] )
  end

  def datasets(group) do
    authorize_group(group)
#     query = """
# SELECT DISTINCT D.Id,D.Name,D.FullName
# FROM ProbeSetFreeze AS D, ProbeFreeze as D2, InbredSet, Tissue, Species
# WHERE
#     InbredSet.Name = '#{group}' and
#     D.ProbeFreezeId = D2.Id
#     AND D2.TissueId = Tissue.Id
#     AND D2.InbredSetId = InbredSet.Id
#     AND D.confidentiality < 1
#     AND D.public > 0
# """
    query = from probesetfreeze in ProbeSetFreeze,
      join: probefreeze in ProbeFreeze,
      on: probesetfreeze."ProbeFreezeId" == probefreeze."Id",
      join: tissue in Tissue,
      on: probefreeze."TissueId" == tissue."Id",
      join: inbredset in InbredSet,
      on:  probefreeze."InbredSetId" == inbredset."Id",
      where: inbredset."Name" == ^group and probesetfreeze.confidentiality < 1 and probesetfreeze.public > 0,
      select: {probesetfreeze.id, probesetfreeze."Name", probesetfreeze."FullName"},
      distinct: true

      Repo.all(query) |> Enum.map(&(Tuple.to_list(&1)))

    # {:ok, rows} = DB.query(query)
    # for r <- rows, do: ( {id,name,full_name} = r ; [id,name,full_name] )
  end

  def dataset_info(dataset_name) do
    authorize_dataset(dataset_name)
    {probesetfreeze_field, probesetfreeze_value} =
      case use_type(dataset_name) do
        { :integer, i } -> {:id, i}
        { :string, s }  -> {:Name, s}
      end

#     query = """
# SELECT D.Id, D.Name, D.FullName, D.ShortName, D.DataScale, D2.TissueId, Tissue.Name, D.public, D.confidentiality
# FROM ProbeSetFreeze as D, ProbeFreeze as D2, Tissue
# WHERE #{subq}
#     AND D.public > 0
#     AND D.ProbeFreezeId = D2.Id
#     AND D2.TissueId = Tissue.Id
#     """
#     {:ok, rows} = DB.query(query)
#     for r <- rows, do: ( {id,name,full_name,short_name,data_scale,tissue_id,tissue_name,public,confidential} = r; [id,name,full_name,short_name,data_scale,tissue_id,tissue_name,public,confidential] )

    query = from probesetfreeze in ProbeSetFreeze,
      join: probefreeze in ProbeFreeze,
      on: probesetfreeze."ProbeFreezeId" == probefreeze."Id",
      join: tissue in Tissue,
      on: probefreeze."TissueId" == tissue."Id",
      where: field(probesetfreeze, ^probesetfreeze_field) == ^probesetfreeze_value and probesetfreeze.public > 0,
      select: {probesetfreeze.id, probesetfreeze."Name", probesetfreeze."FullName",
               probesetfreeze."ShortName", probesetfreeze."DataScale", probefreeze."TissueId",
               tissue."Name", probesetfreeze.public, probesetfreeze.confidentiality}
    Repo.all(query) |> Enum.map(&(Tuple.to_list(&1)))
  end

  def phenotypes(dataset_name, start, stop) do
    authorize_dataset(dataset_name)
    dataset_id =
      case use_type(dataset_name) do
        { :integer, i } -> i
        { :string, _ }  -> ( [[id | tail_]] = dataset_info(dataset_name)
                           id )
      end

    start2 =
      if start == nil do
        0
      else
        start
      end

    stop2 =
      if stop == nil do
        100
      else
        stop
      end

    limit = stop2 - start2 + 1
    query = """
SELECT distinct ProbeSet.Name,
  ProbeSetXRef.Mean, ProbeSetXRef.LRS,
  ProbeSetXRef.PVALUE, ProbeSetXRef.additive, ProbeSetXRef.locus, ProbeSet.Chr_num,
  ProbeSet.Mb, ProbeSet.Symbol,
  ProbeSet.name_num
FROM ProbeSetXRef, ProbeSet
WHERE ProbeSet.Id = ProbeSetXRef.ProbeSetId
  and ProbeSetXRef.ProbeSetFreezeId = #{dataset_id}
  ORDER BY ProbeSet.symbol ASC LIMIT #{limit}
    """
    {:ok, rows} = DB.query(query)
    for r <- rows, do: ( {name,mean,lrs,pvalue,additive,locus,chr,mb,symbol,name_num} = r ;
      %{ name: name,
         name_id: name_num,
         mean: mean,
         "MAX_LRS": lrs,
         "p_value": pvalue,
         additive: additive,
         locus: locus,
         chr: chr,
         "Mb": mb,
         symbol: symbol
      })
  end

  def marker_info(species,marker) do
#       query = """
# SELECT Geno.Chr, Geno.Mb, Species.Id,Geno.source FROM Geno, Species
# WHERE Species.Name = '#{species}'
# AND Geno.Name = '#{marker}'
#      """
     query = from tab_species in Species,
     join: geno in Geno,
     on: tab_species."SpeciesId" == geno."SpeciesId",
     where: tab_species."Name" == ^species and geno."Name" == ^marker,
     select: {geno."Chr", geno."Mb", tab_species.id, geno."Source"}

    # {:ok, rows} = DB.query(query)

    from_tuple_to_structure = fn(query_result) ->
      {chr_name,chr_len,species_id,source} = query_result
      %{
        species: species,
        species_id: species_id,
        source: source,
        marker: marker,
        chr:     chr_name,
        chr_len: chr_len
      }
    end

    Repo.all(query) |> Enum.map(from_tuple_to_structure)

    # for r <- rows, do: ( {chr_name,chr_len,species_id,source} = r;
    #   %{
    #     species: species,
    #     species_id: species_id,
    #     source: source,
    #     marker: marker,
    #     chr:     chr_name,
    #     chr_len: chr_len
    #   } )
  end

  def phenotype_info(dataset_name,marker) do
    authorize_dataset(dataset_name)
    # The GN1 querly looks like
    # query = "SELECT Strain.Name, %sData.value from %sData, Strain, %s, %sXRef WHERE %s.Name = '%s' and %sXRef.%sId = %s.Id and %sXRef.%sFreezeId = %d and  %sXRef.DataId = %sData.Id and %sData.StrainId = Strain.Id order by Strain.Id"
    # but it does not pick up the stderr.
      query = """
SELECT DISTINCT Strain.id, Strain.Name, ProbeSetData.value, ProbeSetSE.error,
  ProbeSetData.Id
FROM (ProbeSetData, ProbeSetFreeze, Strain, ProbeSet, ProbeSetXRef)
LEFT JOIN ProbeSetSE on (ProbeSetSE.DataId = ProbeSetData.Id
  AND ProbeSetSE.StrainId = ProbeSetData.StrainId)
WHERE ProbeSet.Name = '#{marker}'
  AND ProbeSetXRef.ProbeSetId = ProbeSet.Id
  AND ProbeSetXRef.ProbeSetFreezeId = ProbeSetFreeze.Id
  AND ProbeSetFreeze.Name = '#{dataset_name}'
  AND ProbeSetXRef.DataId = ProbeSetData.Id
  AND ProbeSetData.StrainId = Strain.Id
  ORDER BY Strain.Id
      """
    # IO.puts(query)
    {:ok, rows} = DB.query(query)
    for r <- rows, do: ( {strain_id,strain_name,value,stderr,_} = r;
      [strain_id,strain_name,value,stderr]
    )
  end

  def phenotype_info(dataset_name,marker,group) do
    authorize_dataset(dataset_name)
    authorize_group(group)
    [[group_id | _ ] | _] = group_info(group)
    query = """
SELECT DISTINCT Strain.Id, SX.InbredSetId, Strain.Name, V.value, ProbeSetSE.error,
  V.Id
FROM (ProbeSetData as V, ProbeSetFreeze as D, ProbeFreeze as D2, Strain, StrainXRef as SX, ProbeSet, ProbeSetXRef as Locus)
LEFT JOIN ProbeSetSE on (ProbeSetSE.DataId = V.Id
  AND ProbeSetSE.StrainId = V.StrainId)
WHERE ProbeSet.Name = '#{marker}'
  AND Locus.ProbeSetId = ProbeSet.Id
  AND Locus.ProbeSetFreezeId = D.Id
  AND SX.StrainId = Strain.Id
  AND SX.InbredSetId = #{group_id}
  AND D.Name = '#{dataset_name}'
  AND Locus.DataId = V.Id
  AND V.StrainId = Strain.Id
  AND SX.StrainId = Strain.Id
  ORDER BY Strain.Id
    """

    # IO.puts(query)
    {:ok, rows} = DB.query(query)
    for r <- rows, do: ( {strain_id,_,strain_name,value,stderr,_} = r;
      [strain_id,strain_name,value,stderr]
    )
  end

  def menu_species do
    query = form species in Species,
      select: {species."SpeciesId", species."Name", species."MenuName"}
    # {:ok, rows} = DB.query("SELECT speciesid,name,menuname FROM Species")
    # for r <- rows, do: ( {id,name,fullname} = r; [id,name,fullname] )
    Repo.all(query) |> Enum.map(&(Tuple.to_list(&1)))
  end

  def menu_groups(species) do

    query = """
    select distinct InbredSet.id,InbredSet.Name,InbredSet.FullName
    from InbredSet,Species,ProbeFreeze,GenoFreeze,PublishFreeze
    where Species.Name = '#{species}'
      and InbredSet.SpeciesId = Species.Id and InbredSet.Name != 'BXD300'
      and
                       (PublishFreeze.InbredSetId = InbredSet.Id
                        or GenoFreeze.InbredSetId = InbredSet.Id
                        or ProbeFreeze.InbredSetId = InbredSet.Id)
                        group by InbredSet.Name
                        order by InbredSet.Name
"""
    {:ok, rows} = DB.query(query)
    for r <- rows, do: ( {id,name,fullname} = r; [id,name,fullname] )
  end

  def menu_types(species, group) do
    # query = """
    # select distinct Tissue.Name
    # from ProbeFreeze,ProbeSetFreeze,InbredSet,Tissue,Species
    # where Species.Name = '#{species}' and
      # Species.Id = InbredSet.SpeciesId and
      # InbredSet.Name = '#{group}' and
      # ProbeFreeze.TissueId = Tissue.Id and
      # ProbeFreeze.InbredSetId = InbredSet.Id and
      # ProbeSetFreeze.ProbeFreezeId = ProbeFreeze.Id and
      # ProbeSetFreeze.public > 0
      # order by Tissue.Name
    # """
    # {:ok, rows} = DB.query(query)
    # for r <- rows, do: ( {tissue} = r; [tissue] )

    query = from tab_species in Species,
      join: inbredset in InbredSet,
      on: tab_species.id == inbredset."SpeciesId",
      join: probefreeze in ProbeFreeze,
      on: probefreeze."InbredSetId" == inbredset.id,
      join: tissue in Tissue,
      on: probefreeze."TissueId" == tissue.id,
      join: probesetfreeze in ProbeSetFreeze,
      on: probesetfreeze."ProbeFreezeId" == probefreeze.id,
      where: tab_species."Name" == ^species and
             inbredset."Name" == ^group and
             probesetfreeze.public > 0,
      select: {tissue."Name"},
      distinct: true,
      order_by: tissue."Name"

      Repo.all(query) |> Enum.map(&(Tuple.to_list(&1)))
  end

  def menu_datasets(species, group, type) do
    query = """
    select ProbeSetFreeze.Id,ProbeSetFreeze.Name,ProbeSetFreeze.FullName
    from ProbeSetFreeze, ProbeFreeze, InbredSet, Tissue, Species
    where
    Species.Name = '#{species}' and Species.Id = InbredSet.SpeciesId and
    InbredSet.Name = '#{group}' and
    ProbeSetFreeze.ProbeFreezeId = ProbeFreeze.Id and
    Tissue.Name = '#{type}' and
    ProbeFreeze.TissueId = Tissue.Id and ProbeFreeze.InbredSetId = InbredSet.Id and
    ProbeSetFreeze.confidentiality < 1 and ProbeSetFreeze.public > 0 order by
    ProbeSetFreeze.CreateTime desc
    """
    {:ok, rows} = DB.query(query)
    for r <- rows, do: ( {id,name,fullname} = r; [id,name,fullname] )
  end

end

# This module should only contain the MySQL calls to the backend to
# fetch data. Assembling more complex structures should happen in the
# Assemble modules.
#
# All functions return lists of lists, rather than lists of
# tuples. Main reason is that tuples do not go nicely with JSON.

defmodule GnServer.Data.Store do

  alias GnServer.Backend.MySQL, as: DB
  import Ecto.Query
  alias GnServer.Repo
  alias GnServer.Schema.Species
  alias GnServer.Schema.ProbeSetFreeze
  alias GnServer.Schema.InbredSet
  alias GnServer.Schema.ProbeFreeze
  alias GnServer.Schema.GenoFreeze
  alias GnServer.Schema.PublishFreeze
  alias GnServer.Schema.Tissue

  defp use_type(id) do
    try do
      { :integer, String.to_integer(id) }
    rescue
      _ in ArgumentError -> { :string, id }
    end
  end

  defp authorize_group(group_name) do
    if group_name != "BXD" do
      raise "Authorization error for " <> group_name
    end
  end

  defp authorize_dataset(dataset_name) do
    {field_name, field_value} =
      case use_type(dataset_name) do
        { :integer, i } -> {:id, i}
        { :string, s }  -> {:Name,s}
      end
#     query = """
# SELECT DISTINCT D.confidentiality,D.public FROM ProbeSetFreeze AS D
# WHERE #{subq}
# """

    query = from x in ProbeSetFreeze,
      select: {x.confidentiality, x.public},
      where: field(x, ^field_name) == ^field_value,
      distinct: true

    rows = Repo.all(query)
    if Enum.count(rows) != 1 do
      raise "Access error"
    end

    [{confidentiality,public}] = rows
    if public == 0 or confidentiality > 0 do
      raise "Authorization error"
    end
  end

  def species do
    query = from s in Species,
      select: {s."SpeciesId", s."Name", s."FullName"}
    Repo.all(query) |> Enum.map(&(Tuple.to_list &1))
  end

  def groups(species) do
    {species_field, species_value} =
      case use_type(species) do
        { :integer, i } -> {:id, i}
        { :string, s }  -> {:Name, s}
      end

    # note this query can be simplified
#     query = """
# SELECT distinct InbredSet.id,InbredSet.Name,InbredSet.FullName
# FROM InbredSet,Species,ProbeFreeze,GenoFreeze,PublishFreeze
# WHERE #{subq}
# and InbredSet.SpeciesId = Species.Id and InbredSet.Name != 'BXD300'
# and (PublishFreeze.InbredSetId = InbredSet.Id
#      or GenoFreeze.InbredSetId = InbredSet.Id
#      or ProbeFreeze.InbredSetId = InbredSet.Id)
# """
    query = from species in Species,
      join: inbredset in InbredSet,
      on: species.id == inbredset."SpeciesId",
      left_join: publishfreeze in PublishFreeze,
      on: publishfreeze."InbredSetId" == inbredset.id,
      left_join: genofreeze in GenoFreeze,
      on: genofreeze."InbredSetId" == inbredset.id,
      left_join: probefreeze in ProbeFreeze,
      on: probefreeze."InbredSetId" == inbredset.id,
      where: field(species, ^species_field) == ^species_value and inbredset."Name" != "BXD300",
      select: {inbredset.id,inbredset."Name",inbredset."FullName"},
      distinct: true

    Repo.all(query) |> Enum.map(&(Tuple.to_list &1))
  end

  def group_info(group) do
    {inbredset_field, inbredset_value} =
      case use_type(group) do
        { :integer, i } -> {:id, i}
        { :string, s }  -> {:Name, s}
      end
#     query = "
# SELECT DISTINCT Species.speciesid,Species.Name,C.InbredSetid,C.name,C.mappingmethodid,C.genetictype
# FROM Species, InbredSet as C
# WHERE #{subq} and C.SpeciesId = Species.Id"
    query = from species in Species,
      join: inbredset in InbredSet,
      on: species.id == inbredset."SpeciesId",
      where: field(inbredset, ^inbredset_field) == ^inbredset_value,
      select: {species."SpeciesId", species."Name", inbredset."InbredSetId", inbredset."Name", inbredset."MappingMethodId", inbredset."GeneticType"},
      distinct: true
    # for r <- rows, do: ( {species_id,species,group_id,group_name,method_id,genetic_type} = r; [group_id,group_name,species_id,species,method_id,genetic_type] )
    Repo.all(query) |> Enum.map(&(Tuple.to_list(&1)))
  end

  def chr_info(dataset_name) do
    subq =
      case use_type(dataset_name) do
        { :integer, i } -> "C.id = #{i}"
        { :string, s }  -> "C.Name = '#{s}'"
      end

      query = """
SELECT Chr_Length.Name, Length
FROM Chr_Length, InbredSet as C
WHERE #{subq}
AND Chr_Length.SpeciesId = C.SpeciesId
ORDER BY Chr_Length.OrderId
      """
    {:ok, rows} = DB.query(query)
    for r <- rows, do: ( {chr_name,chr_len} = r; [chr_name,chr_len] )
  end

  def datasets(group) do
    authorize_group(group)
#     query = """
# SELECT DISTINCT D.Id,D.Name,D.FullName
# FROM ProbeSetFreeze AS D, ProbeFreeze as D2, InbredSet, Tissue, Species
# WHERE
#     InbredSet.Name = '#{group}' and
#     D.ProbeFreezeId = D2.Id
#     AND D2.TissueId = Tissue.Id
#     AND D2.InbredSetId = InbredSet.Id
#     AND D.confidentiality < 1
#     AND D.public > 0
# """
    query = from probesetfreeze in ProbeSetFreeze,
      join: probefreeze in ProbeFreeze,
      on: probesetfreeze."ProbeFreezeId" == probefreeze."Id",
      join: tissue in Tissue,
      on: probefreeze."TissueId" == tissue."Id",
      join: inbredset in InbredSet,
      on:  probefreeze."InbredSetId" == inbredset."Id",
      where: inbredset."Name" == ^group and probesetfreeze.confidentiality < 1 and probesetfreeze.public > 0,
      select: {probesetfreeze.id, probesetfreeze."Name", probesetfreeze."FullName"},
      distinct: true

      Repo.all(query) |> Enum.map(&(Tuple.to_list(&1)))

    # {:ok, rows} = DB.query(query)
    # for r <- rows, do: ( {id,name,full_name} = r ; [id,name,full_name] )
  end

  def dataset_info(dataset_name) do
    authorize_dataset(dataset_name)
    {probesetfreeze_field, probesetfreeze_value} =
      case use_type(dataset_name) do
        { :integer, i } -> {:id, i}
        { :string, s }  -> {:Name, s}
      end

#     query = """
# SELECT D.Id, D.Name, D.FullName, D.ShortName, D.DataScale, D2.TissueId, Tissue.Name, D.public, D.confidentiality
# FROM ProbeSetFreeze as D, ProbeFreeze as D2, Tissue
# WHERE #{subq}
#     AND D.public > 0
#     AND D.ProbeFreezeId = D2.Id
#     AND D2.TissueId = Tissue.Id
#     """
#     {:ok, rows} = DB.query(query)
#     for r <- rows, do: ( {id,name,full_name,short_name,data_scale,tissue_id,tissue_name,public,confidential} = r; [id,name,full_name,short_name,data_scale,tissue_id,tissue_name,public,confidential] )

    query = from probesetfreeze in ProbeSetFreeze,
      join: probefreeze in ProbeFreeze,
      on: probesetfreeze."ProbeFreezeId" == probefreeze."Id",
      join: tissue in Tissue,
      on: probefreeze."TissueId" == tissue."Id",
      where: field(probesetfreeze, ^probesetfreeze_field) == ^probesetfreeze_value and probesetfreeze.public > 0,
      select: {probesetfreeze.id, probesetfreeze."Name", probesetfreeze."FullName",
               probesetfreeze."ShortName", probesetfreeze."DataScale", probefreeze."TissueId",
               tissue."Name", probesetfreeze.public, probesetfreeze.confidentiality}
    Repo.all(query) |> Enum.map(&(Tuple.to_list(&1)))
  end

  def phenotypes(dataset_name, start, stop) do
    authorize_dataset(dataset_name)
    dataset_id =
      case use_type(dataset_name) do
        { :integer, i } -> i
        { :string, _ }  -> ( [[id | tail_]] = dataset_info(dataset_name)
                           id )
      end

    start2 =
      if start == nil do
        0
      else
        start
      end

    stop2 =
      if stop == nil do
        100
      else
        stop
      end

    limit = stop2 - start2 + 1
    query = """
SELECT distinct ProbeSet.Name,
  ProbeSetXRef.Mean, ProbeSetXRef.LRS,
  ProbeSetXRef.PVALUE, ProbeSetXRef.additive, ProbeSetXRef.locus, ProbeSet.Chr_num,
  ProbeSet.Mb, ProbeSet.Symbol,
  ProbeSet.name_num
FROM ProbeSetXRef, ProbeSet
WHERE ProbeSet.Id = ProbeSetXRef.ProbeSetId
  and ProbeSetXRef.ProbeSetFreezeId = #{dataset_id}
  ORDER BY ProbeSet.symbol ASC LIMIT #{limit}
    """
    {:ok, rows} = DB.query(query)
    for r <- rows, do: ( {name,mean,lrs,pvalue,additive,locus,chr,mb,symbol,name_num} = r ;
      %{ name: name,
         name_id: name_num,
         mean: mean,
         "MAX_LRS": lrs,
         "p_value": pvalue,
         additive: additive,
         locus: locus,
         chr: chr,
         "Mb": mb,
         symbol: symbol
      })
  end

  def marker_info(species,marker) do
      query = """
SELECT Geno.Chr, Geno.Mb, Species.Id,Geno.source FROM Geno, Species
WHERE Species.Name = '#{species}'
AND Geno.Name = '#{marker}'
     """
     query = from tab_species in Species,
     join: geno in Geno,
     on: tab_species."SpeciesId" == geno."SpeciesId",
     where: tab_species."Name" == ^species and geno."Name" == marker,
     select: {geno."Chr", geno."Mb", tab_species.id, geno.source}

    # {:ok, rows} = DB.query(query)
    Repo.all(query) |> Enum.map(&(
      {chr_name,chr_len,species_id,source} = &1
      %{
        species: species,
        species_id: species_id,
        source: source,
        marker: marker,
        chr:     chr_name,
        chr_len: chr_len
      }
    ))

    # for r <- rows, do: ( {chr_name,chr_len,species_id,source} = r;
    #   %{
    #     species: species,
    #     species_id: species_id,
    #     source: source,
    #     marker: marker,
    #     chr:     chr_name,
    #     chr_len: chr_len
    #   } )
  end

  def phenotype_info(dataset_name,marker) do
    authorize_dataset(dataset_name)
    # The GN1 querly looks like
    # query = "SELECT Strain.Name, %sData.value from %sData, Strain, %s, %sXRef WHERE %s.Name = '%s' and %sXRef.%sId = %s.Id and %sXRef.%sFreezeId = %d and  %sXRef.DataId = %sData.Id and %sData.StrainId = Strain.Id order by Strain.Id"
    # but it does not pick up the stderr.
      query = """
SELECT DISTINCT Strain.id, Strain.Name, ProbeSetData.value, ProbeSetSE.error,
  ProbeSetData.Id
FROM (ProbeSetData, ProbeSetFreeze, Strain, ProbeSet, ProbeSetXRef)
LEFT JOIN ProbeSetSE on (ProbeSetSE.DataId = ProbeSetData.Id
  AND ProbeSetSE.StrainId = ProbeSetData.StrainId)
WHERE ProbeSet.Name = '#{marker}'
  AND ProbeSetXRef.ProbeSetId = ProbeSet.Id
  AND ProbeSetXRef.ProbeSetFreezeId = ProbeSetFreeze.Id
  AND ProbeSetFreeze.Name = '#{dataset_name}'
  AND ProbeSetXRef.DataId = ProbeSetData.Id
  AND ProbeSetData.StrainId = Strain.Id
  ORDER BY Strain.Id
      """
    # IO.puts(query)
    {:ok, rows} = DB.query(query)
    for r <- rows, do: ( {strain_id,strain_name,value,stderr,_} = r;
      [strain_id,strain_name,value,stderr]
    )
  end

  def phenotype_info(dataset_name,marker,group) do
    authorize_dataset(dataset_name)
    authorize_group(group)
    [[group_id | _ ] | _] = group_info(group)
    query = """
SELECT DISTINCT Strain.Id, SX.InbredSetId, Strain.Name, V.value, ProbeSetSE.error,
  V.Id
FROM (ProbeSetData as V, ProbeSetFreeze as D, ProbeFreeze as D2, Strain, StrainXRef as SX, ProbeSet, ProbeSetXRef as Locus)
LEFT JOIN ProbeSetSE on (ProbeSetSE.DataId = V.Id
  AND ProbeSetSE.StrainId = V.StrainId)
WHERE ProbeSet.Name = '#{marker}'
  AND Locus.ProbeSetId = ProbeSet.Id
  AND Locus.ProbeSetFreezeId = D.Id
  AND SX.StrainId = Strain.Id
  AND SX.InbredSetId = #{group_id}
  AND D.Name = '#{dataset_name}'
  AND Locus.DataId = V.Id
  AND V.StrainId = Strain.Id
  AND SX.StrainId = Strain.Id
  ORDER BY Strain.Id
    """

    # IO.puts(query)
    {:ok, rows} = DB.query(query)
    for r <- rows, do: ( {strain_id,_,strain_name,value,stderr,_} = r;
      [strain_id,strain_name,value,stderr]
    )
  end

  def menu_species do
    {:ok, rows} = DB.query("SELECT speciesid,name,menuname FROM Species")
    for r <- rows, do: ( {id,name,fullname} = r; [id,name,fullname] )
  end

  def menu_groups(species) do

    query = """
    select distinct InbredSet.id,InbredSet.Name,InbredSet.FullName
    from InbredSet,Species,ProbeFreeze,GenoFreeze,PublishFreeze
    where Species.Name = '#{species}'
      and InbredSet.SpeciesId = Species.Id and InbredSet.Name != 'BXD300'
      and
                       (PublishFreeze.InbredSetId = InbredSet.Id
                        or GenoFreeze.InbredSetId = InbredSet.Id
                        or ProbeFreeze.InbredSetId = InbredSet.Id)
                        group by InbredSet.Name
                        order by InbredSet.Name
"""
    {:ok, rows} = DB.query(query)
    for r <- rows, do: ( {id,name,fullname} = r; [id,name,fullname] )
  end

  def menu_types(species, group) do
    query = """
    select distinct Tissue.Name
    from ProbeFreeze,ProbeSetFreeze,InbredSet,Tissue,Species
    where Species.Name = '#{species}' and Species.Id = InbredSet.SpeciesId and
      InbredSet.Name = '#{group}' and
      ProbeFreeze.TissueId = Tissue.Id and
      ProbeFreeze.InbredSetId = InbredSet.Id and
      ProbeSetFreeze.ProbeFreezeId = ProbeFreeze.Id and
      ProbeSetFreeze.public > 0
      order by Tissue.Name
    """
    {:ok, rows} = DB.query(query)
    for r <- rows, do: ( {tissue} = r; [tissue] )
  end

  def menu_datasets(species, group, type) do
    query = """
    select ProbeSetFreeze.Id,ProbeSetFreeze.Name,ProbeSetFreeze.FullName
    from ProbeSetFreeze, ProbeFreeze, InbredSet, Tissue, Species
    where
    Species.Name = '#{species}' and Species.Id = InbredSet.SpeciesId and
    InbredSet.Name = '#{group}' and
    ProbeSetFreeze.ProbeFreezeId = ProbeFreeze.Id and
    Tissue.Name = '#{type}' and
    ProbeFreeze.TissueId = Tissue.Id and ProbeFreeze.InbredSetId = InbredSet.Id and
    ProbeSetFreeze.confidentiality < 1 and ProbeSetFreeze.public > 0 order by
    ProbeSetFreeze.CreateTime desc
    """
    {:ok, rows} = DB.query(query)
    for r <- rows, do: ( {id,name,fullname} = r; [id,name,fullname] )
  end

end


Remove versioning via git_describe, unused

defmodule ReleaseManager.Utils do
  @moduledoc """
  This module provides helper functions for the `mix release` and
  `mix release.clean` tasks.
  """
  import Mix.Shell,    only: [cmd: 2]

  # Relx constants
  @relx_output_path      "rel"

  @doc """
  Perform some actions within the context of a specific mix environment
  """
  def with_env(env, fun) do
    old_env = Mix.env
    try do
      # Change env
      Mix.env(env)
      fun.()
    after
      # Change back
      Mix.env(old_env)
    end
  end

  @doc """
  Load the current project's configuration
  """
  def load_config() do
    with_env :prod, fn ->
      if File.regular?("config/config.exs") do
        Mix.Config.read! "config/config.exs"
      else
        []
      end
    end
  end

  @doc """
  Call the _elixir mix binary with the given arguments
  """
  def mix(command, :quiet),        do: mix(command, :dev, :quiet)
  def mix(command, :verbose),      do: mix(command, :dev, :verbose)
  def mix(command, env),           do: mix(command, env, :quiet)
  def mix(command, env, :quiet),   do: do_cmd("MIX_ENV=#{env} mix #{command}", &ignore/1)
  def mix(command, env, :verbose), do: do_cmd("MIX_ENV=#{env} mix #{command}", &IO.write/1)
  @doc """
  Change user permissions for a target file or directory
  """
  def chmod(target, flags), do: do_cmd("chmod #{flags} #{target}", &ignore/1)
  @doc """
  Execute `relx`
  """
  def relx(name, version, verbosity, upgrade?, dev) do
    # Setup paths
    config     = rel_file_dest_path "relx.config"
    output_dir = @relx_output_path
    # Determine whether to pass --dev-mode or not
    dev_mode?  = case dev do
      true  -> "--dev-mode"
      false -> ""
    end
    # Convert friendly verbosity names to relx values
    v = case verbosity do
      :silent  -> 0
      :quiet   -> 1
      :normal  -> 2
      :verbose -> 3
      _        -> 2 # Normal if we get an odd value
    end
    # Let relx do the heavy lifting
    relx_path = Path.join([priv_path, "bin", "relx"])
    command = case upgrade? do
      false -> "#{relx_path} release tar -V #{v} --root #{File.cwd!} --config #{config} --relname #{name} --relvsn #{version} --output-dir #{output_dir} #{dev_mode?}"
      true  ->
        last_release = get_last_release(name)
        "#{relx_path} release relup tar -V #{v} --root #{File.cwd!} --config #{config} --relname #{name} --relvsn #{version} --output-dir #{output_dir} --upfrom \"#{last_release}\" #{dev_mode?}"
    end
    case do_cmd command do
      :ok         -> :ok
      {:error, _} ->
        {:error, "Failed to build release. Please fix any errors and try again."}
    end
  end

  @doc "Print an informational message without color"
  def debug(message), do: IO.puts "==> #{message}"
  @doc "Print an informational message in green"
  def info(message),  do: IO.puts "==> #{IO.ANSI.green}#{message}#{IO.ANSI.reset}"
  @doc "Print a warning message in yellow"
  def warn(message),  do: IO.puts "==> #{IO.ANSI.yellow}#{message}#{IO.ANSI.reset}"
  @doc "Print a notice in yellow"
  def notice(message), do: IO.puts "#{IO.ANSI.yellow}#{message}#{IO.ANSI.reset}"
  @doc "Print an error message in red"
  def error(message), do: IO.puts "==> #{IO.ANSI.red}#{message}#{IO.ANSI.reset}"

  @doc """
  Get a list of tuples representing the previous releases:

  ## Examples

      get_releases #=> [{"test", "0.0.1"}, {"test", "0.0.2"}]

  """
  def get_releases(project) do
    release_path = Path.join([File.cwd!, "rel", project, "releases"])
    case release_path |> File.exists? do
      false -> []
      true  ->
        release_path
        |> File.ls!
        |> Enum.reject(fn entry -> entry == "RELEASES" end)
        |> Enum.map(fn version -> {project, version} end)
    end
  end

  @doc """
  Get the most recent release prior to the current one
  """
  def get_last_release(project) do
    [{_,version} | _] = project |> get_releases |> Enum.sort(fn {_, v1}, {_, v2} -> v1 > v2 end)
    version
  end

  @doc """
  Get the local path of the current elixir executable
  """
  def get_elixir_path() do
    System.find_executable("elixir") |> get_real_path
  end

  @doc """
  Writes an Elixir/Erlang term to the provided path
  """
  def write_term(path, term) do
    :file.write_file('#{path}', :io_lib.fwrite('~p.\n', [term]))
  end

  @doc """
  Writes a collection of Elixir/Erlang terms to the provided path
  """
  def write_terms(path, terms) when is_list(terms) do
    format_str = String.duplicate("~p.\n\n", Enum.count(terms)) |> String.to_char_list
    :file.write_file('#{path}', :io_lib.fwrite(format_str, terms |> Enum.reverse))
  end

  @doc """
  Reads a file as Erlang terms
  """
  def read_terms(path) do
    result = case '#{path}' |> :file.consult do
      {:ok, terms} ->
        terms
      {:error, {line, type, msg}} ->
        error "Unable to parse #{path}: Line #{line}, #{type}, - #{msg}"
        exit(:normal)
      {:error, reason} ->
        error "Unable to access #{path}: #{reason}"
        exit(:normal)
    end
    result
  end

  @doc """
  Convert a string to Erlang terms
  """
  def string_to_terms(str) do
    str
    |> String.split("}.")
    |> Stream.map(&(String.strip(&1, ?\n)))
    |> Stream.map(&String.strip/1)
    |> Stream.map(&('#{&1}}.'))
    |> Stream.map(&(:erl_scan.string(&1)))
    |> Stream.map(fn {:ok, tokens, _} -> :erl_parse.parse_term(tokens) end)
    |> Stream.filter(fn {:ok, _} -> true; {:error, _} -> false end)
    |> Enum.reduce([], fn {:ok, term}, acc -> [term|acc] end)
    |> Enum.reverse
  end

  @doc """
  Merges two sets of Elixir/Erlang terms, where the terms come
  in the form of lists of tuples. For example, such as is found
  in the relx.config file
  """
  def merge(old, new) when is_list(old) and is_list(new) do
    do_merge(old, new, []) |> Enum.reverse
  end

  defp do_merge([h|t], new, acc) when is_tuple(h) do
    case :lists.keysearch(elem(h, 0), 1, new) do
      {:value, new_value} ->
        # Value is present in new, so merge the value
        merged = do_merge_term(h, new_value)
        do_merge(t, new, [merged|acc])
      false ->
        # Value doesn't exist in new, so add it
        do_merge(t, new, [h|acc])
    end
  end
  defp do_merge([], _new, acc) do
    acc
  end

  defp do_merge_term(old, new) when is_tuple(old) and is_tuple(new) do
    old
    |> Tuple.to_list
    |> Enum.with_index
    |> Enum.reduce([], fn
        {val, idx}, acc when is_list(val) ->
          merged = val |> Enum.concat(elem(new, idx)) |> Enum.uniq
          [merged|acc]
        {val, idx}, acc when is_tuple(val) ->
          [do_merge_term(val, elem(new, idx))|acc]
        {_val, idx}, acc ->
          [elem(new, idx)|acc]
       end)
    |> Enum.reverse
    |> List.to_tuple
  end

  @doc "Get the priv path of the exrm dependency"
  def priv_path, do: Path.join([__DIR__, "..", "..", "priv"]) |> Path.expand
  @doc "Get the priv/rel path of the exrm dependency"
  def rel_source_path,       do: Path.join(priv_path, "rel")
  @doc "Get the path to a file located in priv/rel of the exrm dependency"
  def rel_source_path(file), do: Path.join(rel_source_path, file)
  @doc "Get the priv/rel/files path of the exrm dependency"
  def rel_file_source_path,       do: Path.join([priv_path, "rel", "files"])
  @doc "Get the path to a file located in priv/rel/files of the exrm dependency"
  def rel_file_source_path(file), do: Path.join(rel_file_source_path, file)
  @doc """
  Get the path to a file located in the rel directory of the current project.
  You can pass either a file name, or a list of directories to a file, like:

      iex> ReleaseManager.Utils.rel_dest_path "relx.config"
      "path/to/project/rel/relx.config"

      iex> ReleaseManager.Utils.rel_dest_path ["<project>", "lib", "<project>.appup"]
      "path/to/project/rel/<project>/lib/<project>.appup"

  """
  def rel_dest_path(files) when is_list(files), do: Path.join([rel_dest_path] ++ files)
  def rel_dest_path(file),                      do: Path.join(rel_dest_path, file)
  @doc "Get the rel path of the current project."
  def rel_dest_path,                            do: Path.join(File.cwd!, "rel")
  @doc """
  Get the path to a file located in the rel/files directory of the current project.
  You can pass either a file name, or a list of directories to a file, like:

      iex> ReleaseManager.Utils.rel_file_dest_path "sys.config"
      "path/to/project/rel/files/sys.config"

      iex> ReleaseManager.Utils.rel_dest_path ["some", "path", "file.txt"]
      "path/to/project/rel/files/some/path/file.txt"

  """
  def rel_file_dest_path(files) when is_list(files), do: Path.join([rel_file_dest_path] ++ files)
  def rel_file_dest_path(file),                      do: Path.join(rel_file_dest_path, file)
  @doc "Get the rel/files path of the current project."
  def rel_file_dest_path,                            do: Path.join([File.cwd!, "rel", "files"])

  # Ignore a message when used as the callback for Mix.Shell.cmd
  defp ignore(_), do: nil

  defp do_cmd(command), do: do_cmd(command, &IO.write/1)
  defp do_cmd(command, callback) do
    case cmd(command, callback) do
      0 -> :ok
      _ -> {:error, "Release step failed. Please fix any errors and try again."}
    end
  end

  defp get_real_path(path) do
    case path |> String.to_char_list |> :file.read_link_info do
      {:ok, {:file_info, _, :regular, _, _, _, _, _, _, _, _, _, _, _}} ->
        path
      {:ok, {:file_info, _, :symlink, _, _, _, _, _, _, _, _, _, _, _}} ->
        {:ok, sym} = path |> String.to_char_list |> :file.read_link
        case sym |> :filename.pathtype do
          :absolute ->
            sym |> IO.iodata_to_binary
          :relative ->
            symlink = sym |> IO.iodata_to_binary
            path |> Path.dirname |> Path.join(symlink) |> Path.expand
        end
    end |> String.replace("/bin/elixir", "")
  end

end

defmodule ReleaseManager.Utils do
  @moduledoc """
  This module provides helper functions for the `mix release` and
  `mix release.clean` tasks.
  """
  import Mix.Shell,    only: [cmd: 2]

  # Relx constants
  @relx_output_path      "rel"

  @doc """
  Perform some actions within the context of a specific mix environment
  """
  def with_env(env, fun) do
    old_env = Mix.env
    try do
      # Change env
      Mix.env(env)
      fun.()
    after
      # Change back
      Mix.env(old_env)
    end
  end

  @doc """
  Load the current project's configuration
  """
  def load_config() do
    with_env :prod, fn ->
      if File.regular?("config/config.exs") do
        Mix.Config.read! "config/config.exs"
      else
        []
      end
    end
  end

  @doc """
  Call the _elixir mix binary with the given arguments
  """
  def mix(command, :quiet),        do: mix(command, :dev, :quiet)
  def mix(command, :verbose),      do: mix(command, :dev, :verbose)
  def mix(command, env),           do: mix(command, env, :quiet)
  def mix(command, env, :quiet),   do: do_cmd("MIX_ENV=#{env} mix #{command}", &ignore/1)
  def mix(command, env, :verbose), do: do_cmd("MIX_ENV=#{env} mix #{command}", &IO.write/1)
  @doc """
  Change user permissions for a target file or directory
  """
  def chmod(target, flags), do: do_cmd("chmod #{flags} #{target}", &ignore/1)
  @doc """
  Execute `relx`
  """
  def relx(name, version, verbosity, upgrade?, dev) do
    # Setup paths
    config     = rel_file_dest_path "relx.config"
    output_dir = @relx_output_path
    # Determine whether to pass --dev-mode or not
    dev_mode?  = case dev do
      true  -> "--dev-mode"
      false -> ""
    end
    # Get the release version
    ver = case version do
      "" -> git_describe
      _  -> version
    end
    # Convert friendly verbosity names to relx values
    v = case verbosity do
      :silent  -> 0
      :quiet   -> 1
      :normal  -> 2
      :verbose -> 3
      _        -> 2 # Normal if we get an odd value
    end
    # Let relx do the heavy lifting
    relx_path = Path.join([priv_path, "bin", "relx"])
    command = case upgrade? do
      false -> "#{relx_path} release tar -V #{v} --root #{File.cwd!} --config #{config} --relname #{name} --relvsn #{ver} --output-dir #{output_dir} #{dev_mode?}"
      true  ->
        last_release = get_last_release(name)
        "#{relx_path} release relup tar -V #{v} --root #{File.cwd!} --config #{config} --relname #{name} --relvsn #{ver} --output-dir #{output_dir} --upfrom \"#{last_release}\" #{dev_mode?}"
    end
    case do_cmd command do
      :ok         -> :ok
      {:error, _} ->
        {:error, "Failed to build release. Please fix any errors and try again."}
    end
  end
  @doc """
  Get the current project revision's short hash from git
  """
  def git_describe do
    System.cmd "git describe --always --tags | sed -e s/^v//"
  end

  @doc "Print an informational message without color"
  def debug(message), do: IO.puts "==> #{message}"
  @doc "Print an informational message in green"
  def info(message),  do: IO.puts "==> #{IO.ANSI.green}#{message}#{IO.ANSI.reset}"
  @doc "Print a warning message in yellow"
  def warn(message),  do: IO.puts "==> #{IO.ANSI.yellow}#{message}#{IO.ANSI.reset}"
  @doc "Print a notice in yellow"
  def notice(message), do: IO.puts "#{IO.ANSI.yellow}#{message}#{IO.ANSI.reset}"
  @doc "Print an error message in red"
  def error(message), do: IO.puts "==> #{IO.ANSI.red}#{message}#{IO.ANSI.reset}"

  @doc """
  Get a list of tuples representing the previous releases:

  ## Examples

      get_releases #=> [{"test", "0.0.1"}, {"test", "0.0.2"}]

  """
  def get_releases(project) do
    release_path = Path.join([File.cwd!, "rel", project, "releases"])
    case release_path |> File.exists? do
      false -> []
      true  ->
        release_path
        |> File.ls!
        |> Enum.reject(fn entry -> entry == "RELEASES" end)
        |> Enum.map(fn version -> {project, version} end)
    end
  end

  @doc """
  Get the most recent release prior to the current one
  """
  def get_last_release(project) do
    [{_,version} | _] = project |> get_releases |> Enum.sort(fn {_, v1}, {_, v2} -> v1 > v2 end)
    version
  end

  @doc """
  Get the local path of the current elixir executable
  """
  def get_elixir_path() do
    System.find_executable("elixir") |> get_real_path
  end

  @doc """
  Writes an Elixir/Erlang term to the provided path
  """
  def write_term(path, term) do
    :file.write_file('#{path}', :io_lib.fwrite('~p.\n', [term]))
  end

  @doc """
  Writes a collection of Elixir/Erlang terms to the provided path
  """
  def write_terms(path, terms) when is_list(terms) do
    format_str = String.duplicate("~p.\n\n", Enum.count(terms)) |> String.to_char_list
    :file.write_file('#{path}', :io_lib.fwrite(format_str, terms |> Enum.reverse))
  end

  @doc """
  Reads a file as Erlang terms
  """
  def read_terms(path) do
    result = case '#{path}' |> :file.consult do
      {:ok, terms} ->
        terms
      {:error, {line, type, msg}} ->
        error "Unable to parse #{path}: Line #{line}, #{type}, - #{msg}"
        exit(:normal)
      {:error, reason} ->
        error "Unable to access #{path}: #{reason}"
        exit(:normal)
    end
    result
  end

  @doc """
  Convert a string to Erlang terms
  """
  def string_to_terms(str) do
    str
    |> String.split("}.")
    |> Stream.map(&(String.strip(&1, ?\n)))
    |> Stream.map(&String.strip/1)
    |> Stream.map(&('#{&1}}.'))
    |> Stream.map(&(:erl_scan.string(&1)))
    |> Stream.map(fn {:ok, tokens, _} -> :erl_parse.parse_term(tokens) end)
    |> Stream.filter(fn {:ok, _} -> true; {:error, _} -> false end)
    |> Enum.reduce([], fn {:ok, term}, acc -> [term|acc] end)
    |> Enum.reverse
  end

  @doc """
  Merges two sets of Elixir/Erlang terms, where the terms come
  in the form of lists of tuples. For example, such as is found
  in the relx.config file
  """
  def merge(old, new) when is_list(old) and is_list(new) do
    do_merge(old, new, []) |> Enum.reverse
  end

  defp do_merge([h|t], new, acc) when is_tuple(h) do
    case :lists.keysearch(elem(h, 0), 1, new) do
      {:value, new_value} ->
        # Value is present in new, so merge the value
        merged = do_merge_term(h, new_value)
        do_merge(t, new, [merged|acc])
      false ->
        # Value doesn't exist in new, so add it
        do_merge(t, new, [h|acc])
    end
  end
  defp do_merge([], _new, acc) do
    acc
  end

  defp do_merge_term(old, new) when is_tuple(old) and is_tuple(new) do
    old
    |> Tuple.to_list
    |> Enum.with_index
    |> Enum.reduce([], fn
        {val, idx}, acc when is_list(val) ->
          merged = val |> Enum.concat(elem(new, idx)) |> Enum.uniq
          [merged|acc]
        {val, idx}, acc when is_tuple(val) ->
          [do_merge_term(val, elem(new, idx))|acc]
        {_val, idx}, acc ->
          [elem(new, idx)|acc]
       end)
    |> Enum.reverse
    |> List.to_tuple
  end

  @doc "Get the priv path of the exrm dependency"
  def priv_path, do: Path.join([__DIR__, "..", "..", "priv"]) |> Path.expand
  @doc "Get the priv/rel path of the exrm dependency"
  def rel_source_path,       do: Path.join(priv_path, "rel")
  @doc "Get the path to a file located in priv/rel of the exrm dependency"
  def rel_source_path(file), do: Path.join(rel_source_path, file)
  @doc "Get the priv/rel/files path of the exrm dependency"
  def rel_file_source_path,       do: Path.join([priv_path, "rel", "files"])
  @doc "Get the path to a file located in priv/rel/files of the exrm dependency"
  def rel_file_source_path(file), do: Path.join(rel_file_source_path, file)
  @doc """
  Get the path to a file located in the rel directory of the current project.
  You can pass either a file name, or a list of directories to a file, like:

      iex> ReleaseManager.Utils.rel_dest_path "relx.config"
      "path/to/project/rel/relx.config"

      iex> ReleaseManager.Utils.rel_dest_path ["<project>", "lib", "<project>.appup"]
      "path/to/project/rel/<project>/lib/<project>.appup"

  """
  def rel_dest_path(files) when is_list(files), do: Path.join([rel_dest_path] ++ files)
  def rel_dest_path(file),                      do: Path.join(rel_dest_path, file)
  @doc "Get the rel path of the current project."
  def rel_dest_path,                            do: Path.join(File.cwd!, "rel")
  @doc """
  Get the path to a file located in the rel/files directory of the current project.
  You can pass either a file name, or a list of directories to a file, like:

      iex> ReleaseManager.Utils.rel_file_dest_path "sys.config"
      "path/to/project/rel/files/sys.config"

      iex> ReleaseManager.Utils.rel_dest_path ["some", "path", "file.txt"]
      "path/to/project/rel/files/some/path/file.txt"

  """
  def rel_file_dest_path(files) when is_list(files), do: Path.join([rel_file_dest_path] ++ files)
  def rel_file_dest_path(file),                      do: Path.join(rel_file_dest_path, file)
  @doc "Get the rel/files path of the current project."
  def rel_file_dest_path,                            do: Path.join([File.cwd!, "rel", "files"])

  # Ignore a message when used as the callback for Mix.Shell.cmd
  defp ignore(_), do: nil

  defp do_cmd(command), do: do_cmd(command, &IO.write/1)
  defp do_cmd(command, callback) do
    case cmd(command, callback) do
      0 -> :ok
      _ -> {:error, "Release step failed. Please fix any errors and try again."}
    end
  end

  defp get_real_path(path) do
    case path |> String.to_char_list |> :file.read_link_info do
      {:ok, {:file_info, _, :regular, _, _, _, _, _, _, _, _, _, _, _}} ->
        path
      {:ok, {:file_info, _, :symlink, _, _, _, _, _, _, _, _, _, _, _}} ->
        {:ok, sym} = path |> String.to_char_list |> :file.read_link
        case sym |> :filename.pathtype do
          :absolute ->
            sym |> IO.iodata_to_binary
          :relative ->
            symlink = sym |> IO.iodata_to_binary
            path |> Path.dirname |> Path.join(symlink) |> Path.expand
        end
    end |> String.replace("/bin/elixir", "")
  end

end


Using module name and function name for default on_error function. fixes #102

defmodule Joken.Plug do
  import Joken
  alias Joken.Token

  @moduledoc """
  A Plug for signing and verifying authentication tokens.

  ## Usage

  There are two possible scenarios:

  1. Same configuration for all routes
  2. Per route configuration

  In the first scenario just add this plug before the dispatch plug.

      defmodule MyRouter do
        use Plug.Router

        plug Joken.Plug, on_verifying: &verify_function/1
        plug :match
        plug :dispatch

        post "/user" do
          # will only execute here if token is present and valid
        end

        match _ do
          # will only execute here if token is present and valid
        end
      end

  In the second scenario, you will need at least plug ~> 0.14 in your deps.
  Then you must plug this AFTER :match and BEFORE :dispatch.

      defmodule MyRouter do
        use Plug.Router

        # route options
        @skip_token_verification %{joken_skip: true}

        plug :match
        plug Joken.Plug, config_module: MyJWTConfig
        plug :dispatch

        post "/user" do
          # will only execute here if token is present and valid
        end

        # see options section below
        match _, private: @skip_token_verification do
          # will NOT try to validate a token
        end
      end

  ## Options

  This plug accepts the following options in its initialization:

  - `on_verifying`: a function used to verify the token. Receives a Token and must return a Token

  - `on_error` (optional): a function that will be called with `conn` and `message`. Must
  return a tuple containing the conn and a binary representing the 401 response. If it's a map,
  it will be turned into json, otherwise, it will be returned as is.

  When using this with per route options you must pass a private map of options
  to the route. The keys that Joken will look for in that map are:

  - `joken_skip`: skips token validation

  - `joken_on_verifying`: Same as `on_verifying` above. Overrides
  `on_verifying` if it was defined on the Plug

  - `joken_on_error`: Same as `on_error` above. Overrides
  `on_error` if it was defined on the Plug
  """
  import Plug.Conn

  @doc false
  def init(opts) do
    on_verifying = Keyword.get(opts, :on_verifying)
    on_error = Keyword.get(opts, :on_error, &Joken.Plug.default_on_error/2)
    {on_verifying, on_error}
  end

  @doc false
  def call(conn, { on_verifying, on_error }) do

    unless Map.has_key?(conn.private, :joken_on_verifying) do
      conn = put_private(conn, :joken_on_verifying, on_verifying)
    end

    unless Map.has_key?(conn.private, :joken_on_error) do
      conn = put_private(conn, :joken_on_error, on_error)
    end

    if Map.get(conn.private, :joken_skip, false) do
      conn
    else
      parse_auth(conn, get_req_header(conn, "authorization"))
    end
  end

  defp parse_auth(conn, ["Bearer " <> incoming_token]) do
    payload_fun = Map.get(conn.private, :joken_on_verifying)

    verified_token = payload_fun.()
    |> with_compact_token(incoming_token)
    |> verify

    evaluate(conn, verified_token)
  end
  defp parse_auth(conn, _header) do
    send_401(conn, "Unauthorized")
  end

  defp evaluate(conn, %Token{ error: nil } = token) do
    assign(conn, :joken_claims, get_claims(token))
  end
  defp evaluate(conn, %Token{ error: message }) do
    send_401(conn, message)
  end

  defp send_401(conn, message) do
    on_error = conn.private[:joken_on_error]

    {conn, message } = case on_error.(conn, message) do
      {conn, map} when is_map(map) ->
        create_json_response(conn, map)
      response ->
        response
    end

    conn
    |> send_resp(401, message)
    |> halt
  end

  defp create_json_response(conn, map) do
    conn = put_resp_content_type(conn, "application/json")
    json = Poison.encode!(map)
    {conn, json}
  end

  @doc false
  def default_on_error(conn, message) do
    { conn, message }
  end
end

defmodule Joken.Plug do
  import Joken
  alias Joken.Token

  @moduledoc """
  A Plug for signing and verifying authentication tokens.

  ## Usage

  There are two possible scenarios:

  1. Same configuration for all routes
  2. Per route configuration

  In the first scenario just add this plug before the dispatch plug.

      defmodule MyRouter do
        use Plug.Router

        plug Joken.Plug, on_verifying: &verify_function/1
        plug :match
        plug :dispatch

        post "/user" do
          # will only execute here if token is present and valid
        end

        match _ do
          # will only execute here if token is present and valid
        end
      end

  In the second scenario, you will need at least plug ~> 0.14 in your deps.
  Then you must plug this AFTER :match and BEFORE :dispatch.

      defmodule MyRouter do
        use Plug.Router

        # route options
        @skip_token_verification %{joken_skip: true}

        plug :match
        plug Joken.Plug, config_module: MyJWTConfig
        plug :dispatch

        post "/user" do
          # will only execute here if token is present and valid
        end

        # see options section below
        match _, private: @skip_token_verification do
          # will NOT try to validate a token
        end
      end

  ## Options

  This plug accepts the following options in its initialization:

  - `on_verifying`: a function used to verify the token. Receives a Token and must return a Token

  - `on_error` (optional): a function that will be called with `conn` and `message`. Must
  return a tuple containing the conn and a binary representing the 401 response. If it's a map,
  it will be turned into json, otherwise, it will be returned as is.

  When using this with per route options you must pass a private map of options
  to the route. The keys that Joken will look for in that map are:

  - `joken_skip`: skips token validation

  - `joken_on_verifying`: Same as `on_verifying` above. Overrides
  `on_verifying` if it was defined on the Plug

  - `joken_on_error`: Same as `on_error` above. Overrides
  `on_error` if it was defined on the Plug
  """
  import Plug.Conn

  @doc false
  def init(opts) do
    on_verifying = Keyword.get(opts, :on_verifying)
    on_error = Keyword.get(opts, :on_error, &default_on_error/2)
    {on_verifying, on_error}
  end

  @doc false
  def call(conn, { on_verifying, on_error }) do

    unless Map.has_key?(conn.private, :joken_on_verifying) do
      conn = put_private(conn, :joken_on_verifying, on_verifying)
    end

    unless Map.has_key?(conn.private, :joken_on_error) do
      conn = put_private(conn, :joken_on_error, on_error)
    end

    if Map.get(conn.private, :joken_skip, false) do
      conn
    else
      parse_auth(conn, get_req_header(conn, "authorization"))
    end
  end

  defp parse_auth(conn, ["Bearer " <> incoming_token]) do
    payload_fun = Map.get(conn.private, :joken_on_verifying)

    verified_token = payload_fun.()
    |> with_compact_token(incoming_token)
    |> verify

    evaluate(conn, verified_token)
  end
  defp parse_auth(conn, _header) do
    send_401(conn, "Unauthorized")
  end

  defp evaluate(conn, %Token{ error: nil } = token) do
    assign(conn, :joken_claims, get_claims(token))
  end
  defp evaluate(conn, %Token{ error: message }) do
    send_401(conn, message)
  end

  defp send_401(conn, message) do
    on_error = conn.private[:joken_on_error]

    {conn, message } = case on_error.(conn, message) do
      {conn, map} when is_map(map) ->
        create_json_response(conn, map)
      response ->
        response
    end

    conn
    |> send_resp(401, message)
    |> halt
  end

  defp create_json_response(conn, map) do
    conn = put_resp_content_type(conn, "application/json")
    json = Poison.encode!(map)
    {conn, json}
  end

  @doc false
  def default_on_error(conn, message) do
    { conn, message }
  end
end


Move Kitto.View.render_template to public interface

defmodule Kitto.View do
  @moduledoc """
  HTML rendering facility.

  This module defines functions to deal with EEx templates used to provide markup
  for the dashboards.

  ## Configuration Options
  * `templates_dir` - Where to look for templates, defaults to "dashboards".
  * `default_layout` - The layout in which to wrap dashboards, defaults to
  "layout" found in the `templates_dir`.
  """

  @templates_dir Application.get_env :kitto, :templates_dir, "dashboards"
  @default_layout Application.get_env :kitto, :default_layout, "layout"

  @doc """
  Returns the EEx compiled output of the layout with template specified
  """
  def render(template, assigns \\ []) do
    @default_layout
    |> path
    |> EEx.eval_file(assigns: assigns ++ [template: render_template(template, assigns)])
  end

  @doc """
  Returns the EEx compiled output of the template specified
  """
  def render_template(template, assigns \\ []) do
    template |> path |> EEx.eval_file(assigns: assigns)
  end

  @doc """
  Returns true if the given template exists in the templates directory
  """
  def exists?(template), do: template |> path |> File.exists?

  defp path(template), do: Path.join templates_path, "#{template}.html.eex"
  defp templates_path, do: Path.join Kitto.root, @templates_dir
end

defmodule Kitto.View do
  @moduledoc """
  HTML rendering facility.

  This module defines functions to deal with EEx templates used to provide markup
  for the dashboards.

  ## Configuration Options
  * `templates_dir` - Where to look for templates, defaults to "dashboards".
  * `default_layout` - The layout in which to wrap dashboards, defaults to
  "layout" found in the `templates_dir`.
  """

  @templates_dir Application.get_env :kitto, :templates_dir, "dashboards"
  @default_layout Application.get_env :kitto, :default_layout, "layout"

  @doc """
  Returns the EEx compiled output of the template specified
  """
  def render(template, assigns \\ []) do
    @default_layout
    |> path
    |> EEx.eval_file(assigns: assigns ++ [template: render_template(template, assigns)])
  end

  @doc """
  Returns true if the given template exists in the templates directory
  """
  def exists?(template), do: template |> path |> File.exists?

  defp render_template(template, assigns \\ []) do
    template |> path |> EEx.eval_file(assigns: assigns)
  end

  defp path(template), do: Path.join templates_path, "#{template}.html.eex"
  defp templates_path, do: Path.join Kitto.root, @templates_dir
end


config riak

config riak

defmodule State do
  defstruct socket_pid: nil
end

defmodule RiakClient do
  @moduledoc """
  Riak Client
  """
  use GenServer

  def start_link(opt \\ []) do
    IO.puts("Starting Riak Client Worker...")
    GenServer.start_link(__MODULE__, :ok, opt)
  end

  def init(:ok) do
    configure(Riak, host: '127.0.0.1', port: 8087)
    IO.puts("Riak Client init")
    { :ok, nil }
  end

#  defmacro __using__(_opts) do
#    quote do

      # Client level functions
      def configure(server, opts) do
        GenServer.call(server, {:configure, Keyword.fetch!(opts, :host), Keyword.fetch!(opts, :port)})
      end

      @doc "Ping a Riak instance"
      def ping(server), do: GenServer.call(server, {:ping})

      def put(server, obj), do: GenServer.call(server, {:store, obj})

      def find(server, bucket, key), do: GenServer.call(server, {:fetch, bucket, key})

      def resolve(server, bucket, key, index) do
        GenServer.call(server, {:resolve, bucket, key, index})
      end

      @doc "Delete an object from a bucket"
      def delete(server, bucket, key), do: GenServer.call(server, {:delete, bucket, key})
      def delete(server, obj), do: GenServer.call(server, {:delete, obj.bucket, obj.key})

      # Riak modules and functions
      defmodule Bucket do
        def list(server), do: GenServer.call(server, {:list_buckets})
        def list(server, timeout), do: GenServer.call(server, {:list_buckets, timeout})

        def keys(server, bucket), do: GenServer.call(server, {:list_keys, bucket})
        def keys(server, bucket, timeout), do: GenServer.call(server, {:list_keys, bucket, timeout})

        def get(server, bucket), do: GenServer.call(server, {:props, bucket})
        #Possible Props: [n_val: 3, allow_mult: false, last_write_wins: false, basic_quorum: false, notfound_ok: true, precommit: [], postcommit: [], pr: 0, r: :quorum, w: :quorum, pw: 0, dw: :quorum, rw: :quorum]}

        def put(server, bucket, props), do: GenServer.call(server, {:set_props, bucket, props})
        def put(server, bucket, type, props), do: GenServer.call(server, {:set_props, bucket, type, props})

        def reset(server, bucket), do: GenServer.call(server, {:reset, bucket})

        defmodule Type do
          def get(server, type), do: GenServer.call(server, {:get_type, type})
          def put(server, type, props), do: GenServer.call(server, {:set_type, type, props})
          def reset(server, type), do: GenServer.call(server, {:reset_type, type})
        end
      end

      defmodule Index do
        def query(server, bucket, {type, name}, key, opts) do
          case GenServer.call(server, {:index_eq_query, bucket, {type, name}, key, opts}) do
            {:ok, {:index_results_v1, keys, terms, continuation}} -> {keys, terms, continuation}
            res -> res
          end
        end
        def query(server, bucket, {type, name}, startkey, endkey, opts) do
          case GenServer.call(server, {:index_range_query, bucket, {type, name}, startkey, endkey, opts}) do
            {:ok, {:index_results_v1, keys, terms, continuation}} -> {keys, terms, continuation}
            res -> res
          end
        end
      end

      defmodule Mapred do
        def query(server, inputs, query), do: GenServer.call(server, {:mapred_query, inputs, query})
        def query(server, inputs, query, timeout) do
          GenServer.call(server, {:mapred_query, inputs, query, timeout})
        end

        defmodule Bucket do
          def query(server, bucket, query), do: GenServer.call(server, {:mapred_query_bucket, bucket, query})
          def query(server, bucket, query, timeout) do
            GenServer.call(server, {:mapred_query_bucket, bucket, query, timeout})
          end
        end
      end

      defmodule Search do
        def query(server, bucket, query, options) do
          GenServer.call(server, {:search_query, bucket, query, options})
        end
        def query(server, bucket, query, options, timeout) do
          GenServer.call(server, {:search_query, bucket, query, options, timeout})
        end

        defmodule Index do
          def list(server), do: GenServer.call(server, {:search_list_indexes})
          def put(server, bucket), do: GenServer.call(server, {:search_create_index, bucket})
          def get(server, bucket), do: GenServer.call(server, {:search_get_index, bucket})
          def delete(server, bucket), do: GenServer.call(server, {:search_delete_index, bucket})
        end

        defmodule Schema do
          def get(server, bucket), do: GenServer.call(server, {:search_get_schema, bucket})

          def create(server, bucket, content) do
            GenServer.call(server, {:search_create_schema, bucket, content})
          end
        end
      end

      defmodule Counter do
        def enable(server, bucket), do: Bucket.put("#{bucket}-counter", [{:allow_mult, true}])

        def increment(server, bucket, name, amount) do
          GenServer.call(server, {:counter_incr, "#{bucket}-counter", name, amount})
        end

        def value(server, bucket, name) do
          case GenServer.call(server, {:counter_val, "#{bucket}-counter", name}) do
            {:ok, val} -> val
            val -> val
          end
        end
      end # Counter

#    end  # quote
#  end # defmacro

  def build_sibling_list([{_md, val}|t], final_list), do: build_sibling_list(t,[val|final_list])
  def build_sibling_list([], final_list), do: final_list

  # Start Link to Riak
  def handle_call({ :configure, host, port }, _from, _state) do
    {:ok, pid} = :riakc_pb_socket.start_link(host, port)
    new_state = %State{socket_pid: pid}
    { :reply, {:ok, pid}, new_state }
  end

  # Ping Riak
  def handle_call({ :ping }, _from, state) do
      { :reply, :riakc_pb_socket.ping(state.socket_pid), state }
  end

  # Store a Riak Object
  def handle_call({:store, obj }, _from, state) do
    case :riakc_pb_socket.put(state.socket_pid, obj.to_robj()) do
      {:ok, new_object} ->
        { :reply, obj.key(:riakc_obj.key(new_object)), state }
      :ok ->
        { :reply, obj, state }
      _ ->
        { :reply, nil, state }
    end
  end

  # Fetch a Riak Object
  def handle_call({:fetch, bucket, key }, _from, state) do
    case :riakc_pb_socket.get(state.socket_pid, bucket, key) do
      {:ok, object} ->
        if :riakc_obj.value_count(object) > 1 do
          { :reply, build_sibling_list(:riakc_obj.get_contents(object),[]), state }
        else
          { :reply, RObj.from_robj(object), state }
        end
      _ -> { :reply, nil, state }
    end
  end

  # Resolve a Riak Object
  def handle_call({:resolve, bucket, key, index }, _from, state) do
    case :riakc_pb_socket.get(state.socket_pid, bucket, key) do
      {:ok, object} ->
        new_object = :riakc_obj.select_sibling(index, object)
        { :reply, :riakc_pb_socket.put(state.socket_pid, new_object), state }
      _ -> { :reply, nil, state }
    end
  end

  # Delete a Riak Object
  def handle_call({:delete, bucket, key }, _from, state) do
    { :reply, :riakc_pb_socket.delete(state.socket_pid, bucket, key), state }
  end

  def handle_call({:list_buckets, timeout}, _from, state) do
    { :reply, :riakc_pb_socket.list_buckets(state.socket_pid, timeout), state}
  end

  def handle_call({:list_buckets}, _from, state) do
    { :reply, :riakc_pb_socket.list_buckets(state.socket_pid), state}
  end

  def handle_call({:list_keys, bucket, timeout}, _from, state) do
    { :reply, :riakc_pb_socket.list_keys(state.socket_pid, bucket, timeout), state}
  end

  def handle_call({:list_keys, bucket}, _from, state) do
    { :reply, :riakc_pb_socket.list_keys(state.socket_pid, bucket), state}
  end

  def handle_call({:props, bucket}, _from, state) do
    { :reply, :riakc_pb_socket.get_bucket(state.socket_pid, bucket), state}
  end

  def handle_call({:set_props, bucket, props}, _from, state) do
    { :reply, :riakc_pb_socket.set_bucket(state.socket_pid, bucket, props), state}
  end

  def handle_call({:set_props, bucket, type, props}, _from, state) do
    { :reply, :riakc_pb_socket.set_bucket(state.socket_pid, {type, bucket}, props), state}
  end

  def handle_call({:reset, bucket}, _from, state) do
    { :reply, :riakc_pb_socket.reset_bucket(state.socket_pid, bucket), state}
  end

  def handle_call({:get_type, type}, _from, state) do
    { :reply, :riakc_pb_socket.get_bucket_type(state.socket_pid, type), state}
  end

  def handle_call({:set_type, type, props}, _from, state) do
    { :reply, :riakc_pb_socket.set_bucket_type(state.socket_pid, type, props), state}
  end

  def handle_call({:reset_type, type}, _from, state) do
    { :reply, :riakc_pb_socket.reset_bucket_type(state.socket_pid, type), state}
  end

  def handle_call({:mapred_query, inputs, query}, _from, state) do
    { :reply, :riakc_pb_socket.mapred(state.socket_pid, inputs, query), state}
  end

  def handle_call({:mapred_query, inputs, query, timeout}, _from, state) do
    { :reply, :riakc_pb_socket.mapred(state.socket_pid, inputs, query, timeout), state}
  end

  def handle_call({:mapred_query_bucket, bucket, query}, _from, state) do
    { :reply, :riakc_pb_socket.mapred_bucket(state.socket_pid, bucket, query), state}
  end

  def handle_call({:mapred_query_bucket, bucket, query, timeout}, _from, state) do
    { :reply, :riakc_pb_socket.mapred_bucket(state.socket_pid, bucket, query, timeout), state}
  end

  def handle_call({:index_eq_query, bucket, {type, name}, key, opts}, _from, state) do
    {:ok, name} = String.to_char_list(name)
    { :reply, :riakc_pb_socket.get_index_eq(state.socket_pid, bucket, {type, name}, key, opts), state}
  end

  def handle_call({:index_range_query, bucket, {type, name}, startkey, endkey, opts}, _from, state) do
    {:ok, name} = String.to_char_list(name)
    { :reply, :riakc_pb_socket.get_index_range(state.socket_pid, bucket, {type, name}, startkey, endkey, opts), state}
  end

  def handle_call({:search_list_indexes}, _from, state) do
    { :reply, :riakc_pb_socket.list_search_indexes(state.socket_pid), state}
  end

  def handle_call({:search_create_index, index}, _from, state) do
    { :reply, :riakc_pb_socket.create_search_index(state.socket_pid, index), state}
  end

  def handle_call({:search_get_index, index}, _from, state) do
    { :reply, :riakc_pb_socket.get_search_index(state.socket_pid, index), state}
  end

  def handle_call({:search_delete_index, index}, _from, state) do
    { :reply, :riakc_pb_socket.delete_search_index(state.socket_pid, index), state}
  end

  def handle_call({:search_get_schema, name}, _from, state) do
    { :reply, :riakc_pb_socket.get_search_schema(state.socket_pid, name), state}
  end

  def handle_call({:search_create_schema, name, content}, _from, state) do
    { :reply, :riakc_pb_socket.create_search_schema(state.socket_pid, name, content), state}
  end

  def handle_call({:search_query, index, query, options}, _from, state) do
    { :reply, :riakc_pb_socket.search(state.socket_pid, index, query, options), state}
  end

  def handle_call({:search_query, index, query, options, timeout}, _from, state) do
    { :reply, :riakc_pb_socket.search(state.socket_pid, index, query, options, timeout), state}
  end

  def handle_call({:counter_incr, bucket, key, amount}, _from, state) do
    { :reply, :riakc_pb_socket.counter_incr(state.socket_pid, bucket, key, amount), state}
  end

  def handle_call({:counter_val, bucket, key}, _from, state) do
    { :reply, :riakc_pb_socket.counter_val(state.socket_pid, bucket, key), state}
  end
end

defmodule State do
  defstruct socket_pid: nil
end

defmodule RiakClient do
  @moduledoc """
  Riak Client
  """
  use GenServer

  def start_link(opt \\ []) do
    IO.puts("Starting Riak Client Worker...")
    GenServer.start_link(__MODULE__, :ok, opt)
  end

  def init() do
    { :ok, nil }
  end

#  defmacro __using__(_opts) do
#    quote do

      # Client level functions
      def configure(server, opts) do
        GenServer.call(server, {:configure, Keyword.fetch!(opts, :host), Keyword.fetch!(opts, :port)})
      end

      @doc "Ping a Riak instance"
      def ping(server), do: GenServer.call(server, {:ping})

      def put(server, obj), do: GenServer.call(server, {:store, obj})

      def find(server, bucket, key), do: GenServer.call(server, {:fetch, bucket, key})

      def resolve(server, bucket, key, index) do
        GenServer.call(server, {:resolve, bucket, key, index})
      end

      @doc "Delete an object from a bucket"
      def delete(server, bucket, key), do: GenServer.call(server, {:delete, bucket, key})
      def delete(server, obj), do: GenServer.call(server, {:delete, obj.bucket, obj.key})

      # Riak modules and functions
      defmodule Bucket do
        def list(server), do: GenServer.call(server, {:list_buckets})
        def list(server, timeout), do: GenServer.call(server, {:list_buckets, timeout})

        def keys(server, bucket), do: GenServer.call(server, {:list_keys, bucket})
        def keys(server, bucket, timeout), do: GenServer.call(server, {:list_keys, bucket, timeout})

        def get(server, bucket), do: GenServer.call(server, {:props, bucket})
        #Possible Props: [n_val: 3, allow_mult: false, last_write_wins: false, basic_quorum: false, notfound_ok: true, precommit: [], postcommit: [], pr: 0, r: :quorum, w: :quorum, pw: 0, dw: :quorum, rw: :quorum]}

        def put(server, bucket, props), do: GenServer.call(server, {:set_props, bucket, props})
        def put(server, bucket, type, props), do: GenServer.call(server, {:set_props, bucket, type, props})

        def reset(server, bucket), do: GenServer.call(server, {:reset, bucket})

        defmodule Type do
          def get(server, type), do: GenServer.call(server, {:get_type, type})
          def put(server, type, props), do: GenServer.call(server, {:set_type, type, props})
          def reset(server, type), do: GenServer.call(server, {:reset_type, type})
        end
      end

      defmodule Index do
        def query(server, bucket, {type, name}, key, opts) do
          case GenServer.call(server, {:index_eq_query, bucket, {type, name}, key, opts}) do
            {:ok, {:index_results_v1, keys, terms, continuation}} -> {keys, terms, continuation}
            res -> res
          end
        end
        def query(server, bucket, {type, name}, startkey, endkey, opts) do
          case GenServer.call(server, {:index_range_query, bucket, {type, name}, startkey, endkey, opts}) do
            {:ok, {:index_results_v1, keys, terms, continuation}} -> {keys, terms, continuation}
            res -> res
          end
        end
      end

      defmodule Mapred do
        def query(server, inputs, query), do: GenServer.call(server, {:mapred_query, inputs, query})
        def query(server, inputs, query, timeout) do
          GenServer.call(server, {:mapred_query, inputs, query, timeout})
        end

        defmodule Bucket do
          def query(server, bucket, query), do: GenServer.call(server, {:mapred_query_bucket, bucket, query})
          def query(server, bucket, query, timeout) do
            GenServer.call(server, {:mapred_query_bucket, bucket, query, timeout})
          end
        end
      end

      defmodule Search do
        def query(server, bucket, query, options) do
          GenServer.call(server, {:search_query, bucket, query, options})
        end
        def query(server, bucket, query, options, timeout) do
          GenServer.call(server, {:search_query, bucket, query, options, timeout})
        end

        defmodule Index do
          def list(server), do: GenServer.call(server, {:search_list_indexes})
          def put(server, bucket), do: GenServer.call(server, {:search_create_index, bucket})
          def get(server, bucket), do: GenServer.call(server, {:search_get_index, bucket})
          def delete(server, bucket), do: GenServer.call(server, {:search_delete_index, bucket})
        end

        defmodule Schema do
          def get(server, bucket), do: GenServer.call(server, {:search_get_schema, bucket})

          def create(server, bucket, content) do
            GenServer.call(server, {:search_create_schema, bucket, content})
          end
        end
      end

      defmodule Counter do
        def enable(server, bucket), do: Bucket.put("#{bucket}-counter", [{:allow_mult, true}])

        def increment(server, bucket, name, amount) do
          GenServer.call(server, {:counter_incr, "#{bucket}-counter", name, amount})
        end

        def value(server, bucket, name) do
          case GenServer.call(server, {:counter_val, "#{bucket}-counter", name}) do
            {:ok, val} -> val
            val -> val
          end
        end
      end # Counter

#    end  # quote
#  end # defmacro

  def build_sibling_list([{_md, val}|t], final_list), do: build_sibling_list(t,[val|final_list])
  def build_sibling_list([], final_list), do: final_list

  # Start Link to Riak
  def handle_call({ :configure, host, port }, _from, _state) do
    {:ok, pid} = :riakc_pb_socket.start_link(host, port)
    new_state = %State{socket_pid: pid}
    { :reply, {:ok, pid}, new_state }
  end

  # Ping Riak
  def handle_call({ :ping }, _from, state) do
      { :reply, :riakc_pb_socket.ping(state.socket_pid), state }
  end

  # Store a Riak Object
  def handle_call({:store, obj }, _from, state) do
    case :riakc_pb_socket.put(state.socket_pid, obj.to_robj()) do
      {:ok, new_object} ->
        { :reply, obj.key(:riakc_obj.key(new_object)), state }
      :ok ->
        { :reply, obj, state }
      _ ->
        { :reply, nil, state }
    end
  end

  # Fetch a Riak Object
  def handle_call({:fetch, bucket, key }, _from, state) do
    case :riakc_pb_socket.get(state.socket_pid, bucket, key) do
      {:ok, object} ->
        if :riakc_obj.value_count(object) > 1 do
          { :reply, build_sibling_list(:riakc_obj.get_contents(object),[]), state }
        else
          { :reply, RObj.from_robj(object), state }
        end
      _ -> { :reply, nil, state }
    end
  end

  # Resolve a Riak Object
  def handle_call({:resolve, bucket, key, index }, _from, state) do
    case :riakc_pb_socket.get(state.socket_pid, bucket, key) do
      {:ok, object} ->
        new_object = :riakc_obj.select_sibling(index, object)
        { :reply, :riakc_pb_socket.put(state.socket_pid, new_object), state }
      _ -> { :reply, nil, state }
    end
  end

  # Delete a Riak Object
  def handle_call({:delete, bucket, key }, _from, state) do
    { :reply, :riakc_pb_socket.delete(state.socket_pid, bucket, key), state }
  end

  def handle_call({:list_buckets, timeout}, _from, state) do
    { :reply, :riakc_pb_socket.list_buckets(state.socket_pid, timeout), state}
  end

  def handle_call({:list_buckets}, _from, state) do
    { :reply, :riakc_pb_socket.list_buckets(state.socket_pid), state}
  end

  def handle_call({:list_keys, bucket, timeout}, _from, state) do
    { :reply, :riakc_pb_socket.list_keys(state.socket_pid, bucket, timeout), state}
  end

  def handle_call({:list_keys, bucket}, _from, state) do
    { :reply, :riakc_pb_socket.list_keys(state.socket_pid, bucket), state}
  end

  def handle_call({:props, bucket}, _from, state) do
    { :reply, :riakc_pb_socket.get_bucket(state.socket_pid, bucket), state}
  end

  def handle_call({:set_props, bucket, props}, _from, state) do
    { :reply, :riakc_pb_socket.set_bucket(state.socket_pid, bucket, props), state}
  end

  def handle_call({:set_props, bucket, type, props}, _from, state) do
    { :reply, :riakc_pb_socket.set_bucket(state.socket_pid, {type, bucket}, props), state}
  end

  def handle_call({:reset, bucket}, _from, state) do
    { :reply, :riakc_pb_socket.reset_bucket(state.socket_pid, bucket), state}
  end

  def handle_call({:get_type, type}, _from, state) do
    { :reply, :riakc_pb_socket.get_bucket_type(state.socket_pid, type), state}
  end

  def handle_call({:set_type, type, props}, _from, state) do
    { :reply, :riakc_pb_socket.set_bucket_type(state.socket_pid, type, props), state}
  end

  def handle_call({:reset_type, type}, _from, state) do
    { :reply, :riakc_pb_socket.reset_bucket_type(state.socket_pid, type), state}
  end

  def handle_call({:mapred_query, inputs, query}, _from, state) do
    { :reply, :riakc_pb_socket.mapred(state.socket_pid, inputs, query), state}
  end

  def handle_call({:mapred_query, inputs, query, timeout}, _from, state) do
    { :reply, :riakc_pb_socket.mapred(state.socket_pid, inputs, query, timeout), state}
  end

  def handle_call({:mapred_query_bucket, bucket, query}, _from, state) do
    { :reply, :riakc_pb_socket.mapred_bucket(state.socket_pid, bucket, query), state}
  end

  def handle_call({:mapred_query_bucket, bucket, query, timeout}, _from, state) do
    { :reply, :riakc_pb_socket.mapred_bucket(state.socket_pid, bucket, query, timeout), state}
  end

  def handle_call({:index_eq_query, bucket, {type, name}, key, opts}, _from, state) do
    {:ok, name} = String.to_char_list(name)
    { :reply, :riakc_pb_socket.get_index_eq(state.socket_pid, bucket, {type, name}, key, opts), state}
  end

  def handle_call({:index_range_query, bucket, {type, name}, startkey, endkey, opts}, _from, state) do
    {:ok, name} = String.to_char_list(name)
    { :reply, :riakc_pb_socket.get_index_range(state.socket_pid, bucket, {type, name}, startkey, endkey, opts), state}
  end

  def handle_call({:search_list_indexes}, _from, state) do
    { :reply, :riakc_pb_socket.list_search_indexes(state.socket_pid), state}
  end

  def handle_call({:search_create_index, index}, _from, state) do
    { :reply, :riakc_pb_socket.create_search_index(state.socket_pid, index), state}
  end

  def handle_call({:search_get_index, index}, _from, state) do
    { :reply, :riakc_pb_socket.get_search_index(state.socket_pid, index), state}
  end

  def handle_call({:search_delete_index, index}, _from, state) do
    { :reply, :riakc_pb_socket.delete_search_index(state.socket_pid, index), state}
  end

  def handle_call({:search_get_schema, name}, _from, state) do
    { :reply, :riakc_pb_socket.get_search_schema(state.socket_pid, name), state}
  end

  def handle_call({:search_create_schema, name, content}, _from, state) do
    { :reply, :riakc_pb_socket.create_search_schema(state.socket_pid, name, content), state}
  end

  def handle_call({:search_query, index, query, options}, _from, state) do
    { :reply, :riakc_pb_socket.search(state.socket_pid, index, query, options), state}
  end

  def handle_call({:search_query, index, query, options, timeout}, _from, state) do
    { :reply, :riakc_pb_socket.search(state.socket_pid, index, query, options, timeout), state}
  end

  def handle_call({:counter_incr, bucket, key, amount}, _from, state) do
    { :reply, :riakc_pb_socket.counter_incr(state.socket_pid, bucket, key, amount), state}
  end

  def handle_call({:counter_val, bucket, key}, _from, state) do
    { :reply, :riakc_pb_socket.counter_val(state.socket_pid, bucket, key), state}
  end
end


Update module name

Update module name

defmodule PanWeb.BotView do
  use Pan.Web, :view

  def render("webhook.json", %{ challenge: challenge}) do
    challenge
  end
end

defmodule Pan.BotView do
  use Pan.Web, :view

  def render("webhook.json", %{ challenge: challenge}) do
    challenge
  end
end


Move tests to Erlang 18 which has proper logger behaviour

defmodule Logger.ErrorHandlerTest do
  use Logger.Case

  test "survives after crashes" do
    assert capture_log(fn ->
      :error_logger.info_msg("~p~n", [])
      wait_for_handler(:error_logger, Logger.ErrorHandler)
    end) =~ "[error] GenEvent handler Logger.ErrorHandler installed at :error_logger\n" <>
            "** (exit) an exception was raised:"
    assert error_log(:info_msg, "~p~n", [:hello]) =~ msg("[info]  :hello")
  end

  test "survives after Logger exit" do
    Process.whereis(Logger) |> Process.exit(:kill)
    wait_for_logger()
    wait_for_handler(:error_logger, Logger.ErrorHandler)
    assert error_log(:info_msg, "~p~n", [:hello]) =~ msg("[info]  :hello")
  end

  test "formats error_logger info message" do
    assert error_log(:info_msg, "hello", []) =~ msg("[info]  hello")
    assert error_log(:info_msg, "~p~n", [:hello]) =~ msg("[info]  :hello")
  end

  test "formats error_logger info report" do
    assert error_log(:info_report, "hello") =~ msg("[info]  \"hello\"")
    assert error_log(:info_report, :hello) =~ msg("[info]  :hello")
    assert error_log(:info_report, :special, :hello) == ""
  end

  test "formats error_logger error message" do
    assert error_log(:error_msg, "hello", []) =~ msg("[error] hello")
    assert error_log(:error_msg, "~p~n", [:hello]) =~ msg("[error] :hello")
  end

  test "formats error_logger error report" do
    assert error_log(:error_report, "hello") =~ msg("[error] \"hello\"")
    assert error_log(:error_report, :hello) =~ msg("[error] :hello")
    assert error_log(:error_report, :special, :hello) == ""
  end

  if :erlang.system_info(:otp_release) >= '18' do
    test "formats error_logger warning message" do
      assert error_log(:warning_msg, "hello", []) =~ msg("[warn]  hello")
      assert error_log(:warning_msg, "~p~n", [:hello]) =~ msg("[warn]  :hello")
    end

    test "formats error_logger warning report" do
      assert error_log(:warning_report, "hello") =~ msg("[warn]  \"hello\"")
      assert error_log(:warning_report, :hello) =~ msg("[warn]  :hello")
      assert error_log(:warning_report, :special, :hello) == ""
    end
  end

  defp error_log(fun, format) do
    do_error_log(fun, [format])
  end

  defp error_log(fun, format, args) do
    do_error_log(fun, [format, args])
  end

  defp do_error_log(fun, args) do
    capture_log(fn -> apply(:error_logger, fun, args) end)
  end
end

defmodule Logger.ErrorHandlerTest do
  use Logger.Case

  test "survives after crashes" do
    assert capture_log(fn ->
      :error_logger.info_msg("~p~n", [])
      wait_for_handler(:error_logger, Logger.ErrorHandler)
    end) =~ "[error] GenEvent handler Logger.ErrorHandler installed at :error_logger\n" <>
            "** (exit) an exception was raised:"
    assert error_log(:info_msg, "~p~n", [:hello]) =~ msg("[info]  :hello")
  end

  test "survives after Logger exit" do
    Process.whereis(Logger) |> Process.exit(:kill)
    wait_for_logger()
    wait_for_handler(:error_logger, Logger.ErrorHandler)
    assert error_log(:info_msg, "~p~n", [:hello]) =~ msg("[info]  :hello")
  end

  test "formats error_logger info message" do
    assert error_log(:info_msg, "hello", []) =~ msg("[info]  hello")
    assert error_log(:info_msg, "~p~n", [:hello]) =~ msg("[info]  :hello")
  end

  test "formats error_logger info report" do
    assert error_log(:info_report, "hello") =~ msg("[info]  \"hello\"")
    assert error_log(:info_report, :hello) =~ msg("[info]  :hello")
    assert error_log(:info_report, :special, :hello) == ""
  end

  test "formats error_logger error message" do
    assert error_log(:error_msg, "hello", []) =~ msg("[error] hello")
    assert error_log(:error_msg, "~p~n", [:hello]) =~ msg("[error] :hello")
  end

  test "formats error_logger error report" do
    assert error_log(:error_report, "hello") =~ msg("[error] \"hello\"")
    assert error_log(:error_report, :hello) =~ msg("[error] :hello")
    assert error_log(:error_report, :special, :hello) == ""
  end

  test "formats error_logger warning message" do
    # Warnings by default are logged as errors by Erlang
    assert error_log(:warning_msg, "hello", []) =~ msg("[error] hello")
    assert error_log(:warning_msg, "~p~n", [:hello]) =~ msg("[error] :hello")
  end

  test "formats error_logger warning report" do
    # Warnings by default are logged as errors by Erlang
    assert error_log(:warning_report, "hello") =~ msg("[error] \"hello\"")
    assert error_log(:warning_report, :hello) =~ msg("[error] :hello")
    assert error_log(:warning_report, :special, :hello) == ""
  end

  defp error_log(fun, format) do
    do_error_log(fun, [format])
  end

  defp error_log(fun, format, args) do
    do_error_log(fun, [format, args])
  end

  defp do_error_log(fun, args) do
    capture_log(fn -> apply(:error_logger, fun, args) end)
  end
end