Skip to content

Instantly share code, notes, and snippets.

@bryanhuntesl
Last active April 24, 2020 09:05
Show Gist options
  • Star 3 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save bryanhuntesl/631b578b62169d5148d54a54b35c30f1 to your computer and use it in GitHub Desktop.
Save bryanhuntesl/631b578b62169d5148d54a54b35c30f1 to your computer and use it in GitHub Desktop.

lib/transfer_resolver.csv:

10D,1,Signed to 10-Day Contract
10D2,2,Signed to Second 10-Day Contract
ABS,3,Leave of Absence
ACT,4,Activated
BRV,5,Placed on Bereavement List
CEXP,6,Contract Expired
CEXT,,Contract Extension
CL,8,Claimed
DEC,9,Deceased

lib/transfer_resolver.ex :

defmodule TransferResolver do
  require Logger

  @external_resource mimes_path =
                       Path.join([
                         __DIR__,
                         "transfer_resolver.csv"
                       ])

  @moduledoc """
  __MODULE__ can resolve team transaction (transfer) names such as "DEC" to the
  corresponding transaction type id used in the database
  """

  Module.register_attribute(__MODULE__, :mappings, accumulate: true, persist: true)

  for line <- File.stream!(mimes_path, [], :line) do
    [type, id | _] = line |> String.split(",") |> Enum.map(&String.trim(&1))
    # id = String.to_integer(id)
    @spec type_to_id(String.t()) :: integer()
    @doc """
    Gives the integer id for a given transaction `name`.

    Returns `an integer`.

    ## Examples
        iex> Foo.type_to_id("DEC")
        7
    """
    @mappings {type, id}

    def type_to_id(unquote(type) = type) when is_binary(type) do
      case unquote(id) do
        "" ->
          Logger.warn("missing id for transfer type #{unquote(type)}")
          nil

        other ->
          String.to_integer(other)
      end
    end
  end

  def type_to_id(other) when is_binary(other) do
    Logger.warn("unable to resolve transfer type '#{other}'")
    nil
  end

  def list_mappings(), do: @mappings
end
@evadne
Copy link

evadne commented Apr 23, 2020

defmodule Transfer.Resolver.Builder do
  defmacro __using__(options) do
    quote do
      {:ok, file_path} = Keyword.fetch(unquote(options), :file_path)
      @external_resource file_path
      @before_compile {unquote(__MODULE__), :build_rules}
      @before_compile {unquote(__MODULE__), :build_rules_catchall}
      @rules unquote(__MODULE__).parse_rules(file_path)
      require Logger
    end
  end

  defmacro build_rules(env) do
    env.module
    |> Module.get_attribute(:rules)
    |> Enum.map(&build_quoted_rule/1)
  end

  defmacro build_rules_catchall(_) do
    build_quoted_catchall()
  end

  def parse_rules(file_path) do
    file_path
    |> File.stream!([], :line)
    |> Enum.flat_map(&parse_rule/1)
  end

  defp parse_rule(line) do
    case line |> String.split(",") |> Enum.map(&String.trim(&1)) do
      [type, "" | _] -> [{type, nil}]
      [type, id | _] -> [{type, id}]
      _ -> []
    end
  end

  defp parse_value(value) do
    with true <- is_binary(value),
         {value, ""} <- Integer.parse(value, 10) do
      {:ok, value}
    else _ ->
      :error
    end
  end

  defp parse_value!(value) do
    {:ok, value} = parse_value(value)
    value
  end

  defp build_quoted_rule({type, nil}) do
    quote do
      def type_to_id(unquote(type)) do
        Logger.warn("missing id for transfer type #{unquote(type)}")
        nil
      end
    end
  end

  defp build_quoted_rule({type, value}) do
    quote do
      def type_to_id(unquote(type)) do
        unquote(parse_value!(value))
      end
    end
  end
  
  defp build_quoted_catchall do
    quote do
      def type_to_id(type) do
        Logger.warn("unable to resolve transfer type '#{type}'")
        nil
      end
    end
  end
end
defmodule Transfer.Resolver do
  file_directory = Application.app_dir(Mix.Project.config()[:app], "priv")
  file_path = Path.join([file_directory, "transfer_resolver.csv"])
  use Transfer.Resolver.Builder, file_path: file_path
end

@evadne
Copy link

evadne commented Apr 23, 2020

@bryanhuntesl minor fix added

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment