Use Ecto in a mix task

1k Views Asked by At

In a Phoenix Framework application I have a model Product with the field name. I want to create a mix task which lists all product names.

In Ruby on Rails this would be the code to solve the problem:

namespace :list do
  desc "List all products"
  task products: :environment do
    Product.all.each do |product|
      puts product.name
    end
  end
end

In Phoenix I can't even get the list of all products from the database. Here is the task code:

lib/mix/tasks/list.product.ex

defmodule Mix.Tasks.List.Product do                                    
  use Mix.Task
  import Mix.Ecto
  alias App.Repo
  alias App.Product

  def run(_args) do
    products = Repo.all(Product)
  end
end

When I run this task I get this error message:

** (UndefinedFunctionError) function Ecto.Queryable.__using__/1 
is undefined or private

What do I have to do to fetch all products from the database in this mix task?

2

There are 2 best solutions below

0
On BEST ANSWER

The hard way:

defmodule Mix.Tasks.MyTask do
  use Mix.Task
  import Ecto.Query
  alias MyApp.Repo

  @start_apps [
    :postgrex,
    :ecto,
    :ecto_sql
  ]

  @repos Application.get_env(:my_app, :ecto_repos, [])

  def run(args) do
    start_services()

    # Run Ecto...

    stop_services()
  end

  defp start_services do
    Enum.each(@start_apps, &Application.ensure_all_started/1)
    Enum.each(@repos, & &1.start_link(pool_size: 2))
  end

  defp stop_services do
    :init.stop()
  end
end

or the easy way ;)

defmodule Mix.Tasks.MyTask do
  use Mix.Task
  import Ecto.Query
  alias MyApp.Repo

  def run(args) do
    Mix.Task.run("app.start")
    # Run Ecto...
  end
end
2
On

Add ensure_started(Repo, []) at the top of your run method. You may also want to import Ecto.Query for some query forms.

defmodule Mix.Tasks.List.Product do                                    
  use Mix.Task
  import Mix.Ecto
  import Ecto.Query
  alias App.Repo
  alias App.Product

  def run(_args) do
    ensure_started(Repo, [])
    products = Repo.all(Product)
  end
end