Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

run_batch override for association loads #133

Closed
giddie opened this issue Oct 20, 2021 · 3 comments
Closed

run_batch override for association loads #133

giddie opened this issue Oct 20, 2021 · 3 comments

Comments

@giddie
Copy link

giddie commented Oct 20, 2021

It would be really nice if we could override batch loading for associations.

Imagine a fusebox with fuses. In my absinthe schema, I specify:

field :fuses, resolve: dataloader(Fusebox)

I can specify a base query in the context module:

defmodule Fusebox
  def dataloader_source() do
    Dataloader.Ecto.new(Repo, query: &dataloader_query/2)
  end

  defp dataloader_query(Fuse, %{} = _params) do
    Fuse |> Fuse.Query.base()
  end
end

However, imagine that later, we decide that for our domain model, a fusebox cannot contain zero fuses, so if none are found for a given Fusebox, we should return a single default fuse. I would now like to override run_batch to override the way this association is loaded, but there is no facility to do that. So this cannot be done from within the context module without changing the API offered to the schema resolvers. Instead I have to change the schema to something like this:

field :fuses, resolve: fn fusebox, _args, %{context: %{loader: loader}} ->
  Dataloader.load(loader, Fusebox, {:one, Fusebox.Fuse}, fusebox: fusebox)
  |> on_load(fn loader ->
    Dataloader.get(loader, Fusebox, {:one, Fusebox.Fuse}, fusebox: fusebox)
  end)
end

Which will then use the "standard" implementation of run_batch that will delegate to the run_batch hook in the context module. This seems like an important limitation of the "magic" association data loading functionality, pushing a change that should affect only the domain logic into the schema layer. If I need to change the way I load the data in order to modify the loading behaviour in the context, it makes me wary of using the association shortcut magic at all :(

@tlvenn
Copy link
Member

tlvenn commented Oct 21, 2021

Hi @giddie,

You should be able to do this by leveraging the callback option of the dataloader helper.

@giddie
Copy link
Author

giddie commented Oct 21, 2021

Hi @tlvenn. Thanks, but that's the problem - it pushes responsibility for a domain logic concern right down into the schema resolution layer. This really should be handled in the context module.

For now I've decided to bypass the magic association helper in the schema and use Dataloader directly, handling all association batch loading at the context level (with some generic helpers). That way the context module can have the final say over all data flow.

I definitely feel that @jfrolich was onto something here: #25 (comment)

@benwilson512
Copy link
Contributor

I would now like to override run_batch to override the way this association is loaded

You can do this:


  def run_batch(Fusebox.Fuse, query, :fuses, fuse_boxes, repo_opts) do
    # run batch boilerplate to load things by association

    # return a [default_goes_here] for each `fuse_box` that returns no items.
  end

  def run_batch(queryable, query, col, inputs, repo_opts) do
    Dataloader.Ecto.run_batch(Repo, queryable, query, col, inputs, repo_opts)
  end

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

3 participants