Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Ecto 3 - Start Repo in custom CLI task

Tags:

elixir

ecto

If you need access to DB for you mix task - you needed to start your ecto repo manually. While we worked with ecto 2 we had ensure_started function.

So custom CLI task with ecto 2 looks like

defmodule App.Task do
  use Mix.Task
  import Mix.Ecto

  def run(args) do
    repos = parse_repo(args)

    Enum.each repos, fn repo ->
      ensure_repo(repo, args)
      ensure_started(repo, []) # was deleted from ecto 3

ensure_started has been deleted from ecto 3. I tried a few approaches but they didn't work for me. Does anybody know a workaround for ecto 3?

Updated

as @starbelly mentioned ensure_started has migrated to Mix.EctoSQL so we need to add extra import Mix.EctoSQL to make it work

defmodule App.Cli.Task do
  import Mix.Ecto
  import Mix.EctoSQL

  def start_ecto do
    repos = parse_repo([])

    Enum.each(repos, fn repo ->
      ensure_repo(repo, [])
      {:ok, _pid, _apps} = ensure_started(repo, [])
    end)
  end
end
like image 785
radzserg Avatar asked Jan 27 '23 00:01

radzserg


2 Answers

The function you're trying to import and call has been moved into ecto_sql. You should import Mix.EctoSQL for ensure_started/2

Example:

defmodule Mix.Tasks.Friends.Hello do
  use Mix.Task
  import Mix.Ecto
  import Mix.EctoSQL

  def run(args) do
    repos = parse_repo(args)

    Enum.each(repos, fn repo ->
      ensure_repo(repo, args)
      {:ok, _pid, _apps} = ensure_started(repo, [])
      Friends.Repo.all(Friends.Person)
    end)
  end
end
like image 71
starbelly Avatar answered Mar 17 '23 02:03

starbelly


None of these approaches will work anymore in the latest version of ecto_sql (3.1.2) because Mix.EctoSQL.ensure_started/2 was a private function, not meant for use outside of Ecto.

As per Jose, the correct approach is to use

Mix.Task.run("app.start")

So the example @starbelly shared would be modified to be

defmodule Mix.Tasks.Friends.Hello do
  use Mix.Task

  def run(args) do
    Mix.Task.run("app.start")
    repos = parse_repo(args)

    Enum.each(repos, fn repo ->
      repo.all(Friends.Person)
    end)
  end
end

The big drawback to this approach is it will start your entire application, including any background processes you have. As a result, you may need to modify your application.ex file to not start those if started by a mix task.

like image 29
Dennis Beatty Avatar answered Mar 17 '23 02:03

Dennis Beatty