Can I use dataloader to query for a relation of a relation?

Does anyone know if I can use dataloader to load a relation of a relation?

I have code that’s like this:

  def load_relations(
        struct_or_list,
        relations,
        %{context: %{loader: loader}},
        post_process \\ & &1
      ) do
    load_all(struct_or_list, relations, loader)
    |> on_load(fn loader ->
      Enum.reduce(relations, struct_or_list, fn relation, parent ->
        %{parent | relation => Dataloader.get(loader, :nest_db, relation, struct_or_list)}
      end)
      |> post_process.()
    end)
  end

  defp load_all(struct_or_list, relations, loader) do
    Enum.reduce(relations, loader, fn
      relation, loader ->
        Dataloader.load(loader, :nest_db, relation, struct_or_list)
    end)
  end

which allows me to do this:

    field(:thing, :thing) do
      resolve(
        load_relations( [:first_relation, :second_relation], fn thing -> ...whatever end)
     )
    end

that works but I want to turn it into this:

    field(:thing, :thing) do
      resolve(
        load_relations( [:first_relation, second_relation: [:nested_third_relation]], fn thing -> ...whatever end)
     )
    end

I’ve tried doing this:

  defp load_all(struct_or_list, relations, loader) do
    Enum.reduce(relations, loader, fn
      {relation, nested_relations}, loader ->
        load_all(
         # At this point we want the struct or list to be a different struct...
          struct_or_list,
          nested_relations,
          Dataloader.load(loader, :nest_db, relation, struct_or_list)
        )

      relation, loader ->
        Dataloader.load(loader, :nest_db, relation, struct_or_list)
    end)
  end

But that fails because of the comment above.

Am I barking up the wrong proverb?

Take a look at https://hexdocs.pm/dataloader/Dataloader.Ecto.html#module-filtering-ordering

Instead of order you could do something like preload and pick it up in your query/2

3 Likes

Thanks, I think the run_batch function could help! https://hexdocs.pm/dataloader/Dataloader.Ecto.html#module-custom-batch-queries but still feels like a strange place to add that functionality though. Like it’s far away from where I want to write what relations I want to load, with no hint that that run_batch thing is running.

E.g. I do this:

source = Dataloader.Ecto.new(MyApp.Repo, [
  run_batch: &MyModule.run_batch/5
])

I then need to pattern match that run_batch function because it will be called any time we call Dataloader.load (I think). So to understand what’s actually happening when loading something, I need to know this:

  loader
  |> Dataloader.load(.... stuff)
  |> Dataloader.run()

and also know about that hidden run_batch thing.

I’m not entirely sure based on the code samples what you exactly need but I made you an example of what I meant in the first post:

:warning: untested code