如何在自定义混合任务中从Ecto获取数据

Mik*_*ona 11 elixir-mix elixir phoenix-framework

我想在自定义混合任务中通过Ecto显示来自我的数据库的数据.如何在我的任务中获得Ecto仓库(或启动它)?

我试过这样的东西,但它不起作用:

defmodule Mix.Tasks.Users.List do


use Mix.Task
  use Mix.Config
  use Ecto.Repo, otp_app: :app

  @shortdoc "List active users"
  @moduledoc """
    List active users
  """
  def run(_) do
    import Ecto.Query, only: [from: 1]

    Mix.shell.info "=== Active users ==="
    query = from u in "users"
    sync = all(query)
    Enum.each(users, fn(s) -> IO.puts(u.name) end)
  end

end
Run Code Online (Sandbox Code Playgroud)

当我启动mix users.list时,这会给我以下输出:

** (ArgumentError) repo Mix.Tasks.Users.List is not started, please ensure it is part of your supervision tree
    lib/ecto/query/planner.ex:64: Ecto.Query.Planner.query_lookup/5
    lib/ecto/query/planner.ex:48: Ecto.Query.Planner.query_with_cache/6
    lib/ecto/repo/queryable.ex:119: Ecto.Repo.Queryable.execute/5
Run Code Online (Sandbox Code Playgroud)

有什么想法或其他方法来解决这个问题?

spl*_*tte 14

Ecto 3.x:

ensure_started已从Ecto中删除.围绕这个主题存在很多混淆.有关更多信息,请参见https://github.com/elixir-ecto/ecto/pull/2829#issuecomment-456313417.José建议使用Mix.Task.run "app.start"或使用repo 启动应用程序MyApp.Repo.start_link(...).

Ecto 2.x:

这曾经在2.x中工作,但显然Mix.Ecto不被认为是公共API的一部分.

实际上有一个辅助模块Mix.Ecto(https://github.com/elixir-ecto/ecto/blob/master/lib/mix/ecto.ex),可以更轻松地编写使用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
Run Code Online (Sandbox Code Playgroud)

此帮助,您可以访问parse_repo/1,ensure_repo/2,ensure_started/1.parse_repo将让你的任务很好地适应其他ecto mix任务,例如它会让你传递-r来指定一个不同的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.
Run Code Online (Sandbox Code Playgroud)

ensure_started 确保仓库正在运行,这是你缺乏的.

有关指导和灵感,您可以在https://github.com/elixir-ecto/ecto/tree/master/lib/mix/tasks查看其他ecto mix任务的实现方式.


den*_*lin 9

作为Jason Harrelson回答的补充:它也有必要开始PostgrexEcto.

[:postgrex, :ecto]
|> Enum.each(&Application.ensure_all_started/1)

MyApp.Repo.start_link
Run Code Online (Sandbox Code Playgroud)

更新:

另一种方法是使用mix任务来启动应用程序:

Mix.Task.run "app.start", []
Run Code Online (Sandbox Code Playgroud)