How to get data from Ecto in a custom mix task
As addition to Jason Harrelson
's answer: it's also necessary to start Postgrex
and Ecto
.
[:postgrex, :ecto]
|> Enum.each(&Application.ensure_all_started/1)
MyApp.Repo.start_link
UPDATE:
Another approach is to use mix task to start application:
Mix.Task.run "app.start", []
Ecto 3.x:
ensure_started
has since been removed from Ecto. There has been a lot of confusion around this topic. See here https://github.com/elixir-ecto/ecto/pull/2829#issuecomment-456313417 for more. José suggests to either start the app using Mix.Task.run "app.start"
or run the repo using MyApp.Repo.start_link(...)
.
Ecto 2.x:
This used to work in 2.x, but apparently Mix.Ecto
was not considered part of the public API.
There is actually a helper module Mix.Ecto
(https://github.com/elixir-ecto/ecto/blob/master/lib/mix/ecto.ex) that makes it easier to write mix tasks that use ecto:
defmodule Mix.Tasks.Users.List do
use Mix.Task
import Mix.Ecto
def run(args) do
repos = parse_repo(args)
Enum.each repos, fn repo ->
Mix.shell.info "=== Active users ==="
ensure_repo(repo, args)
ensure_started(repo, [])
users = repo.all(Ectotask.User)
Enum.each(users, fn(s) -> IO.puts(s.name) end)
end
end
end
This helper gives you access to parse_repo/1
, ensure_repo/2
, ensure_started/1
. parse_repo
will let your task fit in nicely with other ecto mix tasks, for example it will let you pass -r to specify a different repo.
➤ mix users.list
=== Active users ===
Adam
➤ mix users.list -r Ectotask.Repo22
=== Active users ===
** (Mix) could not load Ectotask.Repo22, error: :nofile. Please pass a repo with the -r option.
ensure_started
makes sure the repo is running, which you were lacking.
For guidance and inspiration, you can look at how other ecto mix tasks are implemented at https://github.com/elixir-ecto/ecto/tree/master/lib/mix/tasks