defmodule Mix.Tasks.Recall.Migrate do
@shortdoc "Runs the repository's pending Recall migrations"
@moduledoc """
Runs pending migrations for the given Recall-backed repository.
The stock `mix ecto.migrate` tracks applied versions with a string-source
`schema_migrations` query that this adapter refuses to serve; this task is the
Recall equivalent, doing version bookkeeping through a schema-backed
migrations table (see `Recall.Migrator`). It otherwise behaves like
`ecto.migrate`.
mix recall.migrate
mix recall.migrate -r MyApp.Repo --step 2
## Options
* `-r`, `--repo` — the repo to migrate (defaults to the app's configured repos)
* `--all` — run all pending migrations (the default)
* `--step` — run N pending migrations
* `--to` — run up to and including a target version
* `--migrations-path` — a migrations directory (may be given more than once)
* `--log-level` — the `Logger` level for migration logs (default `info`)
"""
use Mix.Task
import Mix.Ecto
@aliases [r: :repo, n: :step, v: :to]
@switches [
all: :boolean,
step: :integer,
to: :integer,
repo: [:string, :keep],
migrations_path: [:string, :keep],
log_level: :string
]
@impl true
def run(args) do
repos = parse_repo(args)
{opts, _} = OptionParser.parse!(args, strict: @switches, aliases: @aliases)
opts =
opts
|> normalize_log_level()
|> normalize_paths()
for repo <- repos do
ensure_repo(repo, args)
Ecto.Migrator.with_repo(repo, fn repo ->
Recall.Migrator.run(repo, :up, opts)
end)
end
end
defp normalize_log_level(opts) do
case Keyword.pop(opts, :log_level) do
{nil, opts} -> opts
{level, opts} -> Keyword.put(opts, :log, String.to_existing_atom(level))
end
end
defp normalize_paths(opts) do
case Keyword.get_values(opts, :migrations_path) do
[] -> Keyword.delete(opts, :migrations_path)
paths -> opts |> Keyword.delete(:migrations_path) |> Keyword.put(:migrations_paths, paths)
end
end
end