defmodule Mix.Tasks.Ecto.Migrate.Arango do @moduledoc """ Runs Migration/Rollback functions from migration modules """ use Mix.Task import Mix.ArangoXEcto @shortdoc "Runs Migration/Rollback functions from migration modules" @aliases [ d: :dir ] @switches [ dir: :string ] @impl true def run(args) do Mix.Task.run("app.start") case migrated_versions() do [nil] -> Mix.raise("ArangoXEcto is not set up, run `mix ecto.setup.arango` first.") _ -> migrate(args) end end defp migrate(args) do case OptionParser.parse!(args, aliases: @aliases, strict: @switches) do {[], []} -> up() {[dir: "up"], _} -> up() {_, ["up"]} -> up() {[dir: "down"], _} -> down() {_, ["down"]} -> down() {_, ["rollback"]} -> down() {_, _} -> Mix.raise("Unknown arguments provided, #{inspect(Enum.join(args, " "))}") end end defp up do migrated = migrated_versions() pending_migrations() |> Enum.filter(fn file_path -> t_stamp = timestamp(file_path) not Enum.member?(migrated, t_stamp) end) |> maybe_up_migrations() end defp maybe_up_migrations([]), do: Mix.shell().info("No migrations to action :)") defp maybe_up_migrations(migrations) do Enum.each(migrations, fn file_path -> case apply(migration_module(file_path), :up, []) do :ok -> file_path |> timestamp() |> update_versions() Mix.shell().info("Successfully Migrated #{file_path}") {:error, reason} -> Mix.shell().info("Unable to Migrate #{file_path}") Mix.shell().error("Status: " <> inspect(reason)) end end) end def down do [last_migrated_version | _] = versions() module = last_migrated_version |> migration_path() |> migration_module() case apply(module, :down, []) do :ok -> remove_version(last_migrated_version) Mix.shell().info("Successfully Rolled Back #{last_migrated_version}") _ -> Mix.shell().info("Unable to Rollback #{last_migrated_version}") end end defp migration_module(path) do {{:module, module, _, _}, _} = get_default_repo!() |> path_to_priv_repo() |> Path.join("migrations") |> Path.join(path) |> Code.eval_file() module end defp migration_path(version) when not is_binary(version) do version |> to_string() |> migration_path() end defp migration_path(version) do get_default_repo!() |> path_to_priv_repo() |> Path.join("migrations") |> File.ls!() |> Enum.find(&String.starts_with?(&1, version)) end defp pending_migrations do get_default_repo!() |> path_to_priv_repo() |> Path.join("migrations") |> File.ls!() |> Enum.filter(&(!String.starts_with?(&1, "."))) # |> Enum.filter(&(timestamp(&1) not in versions())) |> Enum.sort(&(timestamp(&1) <= timestamp(&2))) end defp timestamp(path) do path |> String.split("_") |> hd() |> String.to_integer() end defp versions do migrated_versions() |> Enum.sort(&(&1 >= &2)) end end