How to insert data using a mix task into parent application from a library?

In my current directory, I have two applications with me (Please find the Github repo here):

  1. people_feeder - A library that I’m writing to insert hardcoded dummy data into projects using a mix task
  2. profile - Just a phoenix app written to make use of the library

Inside people_feeder/lib/mix/tasks/people.insert_data, this is the code that I’ve written for my mix task to run:

defmodule Mix.Tasks.People.InsertData do
  use Mix.Task

  @all_seed_params [
    %{
      name: "Bob",
      age: 19
    },

    %{
      name: "Alice",
      age: 18
    },

    %{
      name: "Nicole",
      age: 21
    }
  ]

  def run(_argv) do
    otp_app = Application.get_env(:people_feeder, :otp_app)
    repo = Application.get_env(:people_feeder, :repo)
    schema = Application.get_env(:people_feeder, :schema)

    Application.ensure_all_started(otp_app)

    insert_people(repo, schema)
  end

  def insert_people(repo, schema) do
    Enum.map(@all_seed_params, fn seed_params ->
      schema_struct = struct(schema)
      changeset = Ecto.Changeset.change(schema_struct, seed_params)

      apply(repo, :insert, [changeset, [on_conflict: :replace_all, conflict_target: :id]])
    end)

  end
end

To make sure the mix task will run with all the configs. I have configured in profile/config/config.exs with the below configurations:

# Configuration for PeopleFeeder
config :people_feeder,
  otp_app: :profile,
  repo: Profile.Repo,
  schema: Profile.People.Person

Note: The schema and repo is present in my application.

When I run the mix task by running the command mix people.insert_data. I’m getting the below error in my console:

** (UndefinedFunctionError) function Profile.People.Person.__struct__/0 is undefined (module Profile.People.Person is not available)
    Profile.People.Person.__struct__()
    (elixir 1.14.0) lib/kernel.ex:2350: Kernel.struct/3
    (people_feeder 0.1.0) lib/mix/tasks/people.insert_data.ex:33: anonymous fn/3 in Mix.Tasks.People.InsertData.insert_people/2
    (elixir 1.14.0) lib/enum.ex:1658: Enum."-map/2-lists^map/1-0-"/2
    (mix 1.14.0) lib/mix/task.ex:421: anonymous fn/3 in Mix.Task.run_task/4
    (mix 1.14.0) lib/mix/cli.ex:84: Mix.CLI.run_task/2

I’m not sure what I’m missing. I don’t understand why my dependency is not able to call a function defined in its parent application. Can anyone please help?

Please let me know if you need more information

You need to make sure that the parent application itself is also compiled and started, because you are using its repo and its structs.

Thank you for the reply @benwilson512. I’m not sure how to ensure my parent application is compiled and started. I am having this line in my code written for the mix task:

Application.ensure_all_started(otp_app) # The OTP app comes from the config

Can you please tell me how do I proceed?

Mix.Task.run("compile") will compile the application.

@Marcus @benwilson512

I tried to read the documentation of Mix.Task and found out that mix tasks do not automatically start the parent application. I needed to add this below line of code in my mix task to start the parent application.

@requirements ["app.start"]
3 Likes