Create mix tasks that invoke existing modules which use Ecto

ecto
mix
task
#1

I have a simple module that, when invoked, lists all records in a table.

defmodule App.Adapter do
  alias App.Repo

  def list_all(model) do
    Repo.all(model)
  end
end

I want to have a simple mix task such that I can invoke this function.

defmodule Mix.Tasks.ListAllThings do
  use Mix.Task

  def run(_) do
    App.Adapter.list_all(App.Thing)
  end
end

If I try to invoke this task (and the task does exist), the error is (RuntimeError) could not lookup App.Repo because it was not started or it does not exist. I have a supervisor and am able to run these queries from iex -S mix in the console. Everything I have looked up about this so far has suggested using import Mix.Ecto but none of the helper method seem to behave to me (#ensure_started doesn’t make sense to me).

This list_all task is meant as a quick proof of concept for a small app that essentially just acts as a bundle of scripts to interface with a DB on the fly (no API involved and the app does not persist on a machine for any period of time beyond running the script). Am I just tangling myself in an anti-pattern? If I want to just write elixir scripts to interface with a DB should I be approaching this with something other than tasks?

0 Likes

#2

I’m still curious about this but having hacked at this a bit it seems like using mix run to run scripts is a more felicitous approach for my use case.

0 Likes

#3

You need to make sure to start Repo before using it in a Mix task:

def run(_) do
 Mix.Ecto.ensure_started(App.Repo, [])
 App.Adapter.list_all(App.Thing)
end
0 Likes

Proposal: Private modules (general discussion)
#5

WARNING: In Ecto 2.X you should not reference Mix.Ecto because it is a private API: https://github.com/elixir-ecto/ecto/issues/1586#issuecomment-233301683

And in Ecto 3.X, while Mix.Ecto is now considered public (i.e. no longer has @moduledoc false), the ensure_started function has been removed. Off the top of my head I’m not sure what you should use instead (but maybe it is Mix.Task.run).

1 Like