johnhamelink
5/30/2016 - 2:54 PM

migrate_contact_details.ex

defmodule Mix.Tasks.MigrateContactDetails do
  use Mix.Task
  import Ecto.Query, only: [from: 2]

  @shortdoc "Migrate ContactDetails data into NewContactDetails"

  def run(), do: run(0)
  def run(_args) do
    Mix.Task.run "app.start", []

    Mix.shell.info """
      Converting data from ContactDetails into the NewContactDetails format
    """

    transaction =
      DB.Repo.all(from u in DB.Session, select: u.id)
      |> Enum.map(&convert_record/1)
      |> Enum.reduce(Ecto.Multi.new, &Ecto.Multi.append/2)
      |> DB.Repo.transaction

    case transaction do
      {:ok, _} ->
        Mix.shell.info "All done! The transaction has been applied."
      {:error, failed_operation, failed_value, changes_so_far} ->
        Mix.shell.error "One of the operations failed.:"
        Mix.shell.error "Operation: #{inspect(failed_operation)}"
        Mix.shell.error "Value: #{inspect(failed_value)}"
        Mix.shell.error "The transaction has been rolled back."
    end
  end

  def convert_record(user_id) do
    # Retrieve all the old records associated with the user
    old_records =
    DB.Repo.all(from cd in DB.ContactDetail,
    where: cd.session_id == ^user_id)

    # Reduce them down into a single record in the new
    # format.
    new_record = Enum.reduce(
      old_records,
      %DB.NewContactDetail{session_id: user_id},
      &build_new_record/2
    )

    Ecto.Multi.insert(
      Ecto.Multi.new,
      String.to_atom("user_#{user_id}"),
      new_record
    )
  end

  def build_new_record(old, new) do
    case old.key do
      "email" ->
        %{new | email: old.value}
      "phone_number" ->
        %{new | phone_number: old.value}
      "mailchimp_unique_email_id" ->
        %{new | mailchimp_unique_email_id: old.value}
      other ->
        Mix.shell.warn """
        Don't know what #{inspect(other)} is - not adding it to the new record.
        """
        new
    end
  end

end