AlexDev
AlexDev

Reputation: 4727

Migrate data from another Repo in Ecto migration

Similar to this question: Using a Repo in an Ecto migration, I've got an Ecto migration where I'd like create some new tables but also migrate some data from a different repository. For example:

defmodule MyApp.Repo.Migrations.CreateFoo do
  use Ecto.Migration
  import Ecto.Query

  def change do
    create table(:foo) do
      add(:status, :text)
    end

    flush()
    execute &import_from_AnotherApp/0
  end

  defp import_from_AnotherApp()
    foos = from(f in AnotherApp.Foo, where: ...)
           |> AnotherApp.Repo.all

    Enum.each(foos, fn(foo) ->
      # Insert data from AnotherApp into MyApp foo table
    end)

  end
end

The problem is when running mix ecto.migrate I get

** (RuntimeError) could not lookup Ecto repo AnotherApp.Repo because it was not started or it does not exist

I tried adding AnotherApp as a dependency of MyApp in mix.exs but I still get the same error.

Can this be done?

Upvotes: 0

Views: 953

Answers (2)

Alan Paiva
Alan Paiva

Reputation: 41

Maybe with_repo(repo, fun, opts \\ []) should do it for you https://hexdocs.pm/ecto_sql/Ecto.Migrator.html#with_repo/3

Upvotes: 1

Everett
Everett

Reputation: 9628

When you run mix tasks, they run in their own processes, so other applications (including the main application housing the task) may not be started.

Sometimes you have to put lines like these into your custom mix tasks and I suspect you could put them into your migrations:

{:ok, _} = Application.ensure_all_started(:my_app)
{:ok, _} = Application.ensure_all_started(:another_app)

However, sometimes ensuring that they have started isn't enough: sometimes you have to explicitly start the process. In your case, you'd have to start up the other app's Ecto.Repo. Usually, you start your Ecto repos by listing them in your app's supervisor inside application.ex, e.g.

def start(_type, _args) do
  children = [
    {MyApp.Repo, []},
    {AnotherApp.Repo, []},
  ]

  opts = [strategy: :one_for_one, name: MyApp.Supervisor]
  Supervisor.start_link(children, opts)
end

But if that other app doesn't need to be started for your app's regular functionality, then you can start the process manually by running MyApp.Repo.start_link([]). -- you could put that into your migration to see if it comes up:

x = MyApp.Repo.start_link([])
IO.inspect(x)

With luck, you'll get an :ok and a process id, but if not, you should get some useful debugging info.

Hope that helps.

Upvotes: 2

Related Questions