elixirectodataloaderabsinthe

Elixir + Absinthe + Ecto + Dataloader – filter by multiple fields


Using Elixir/Absinthe/Ecto/Dataloader, how do you query/filter a source by multiple fields?

Example:

Let's say you would want to filter a schema (and dataloader source) named User by two fields, one named is_admin (only true values) and one group_id that can be any value in a list, e.g [1, 5, 9]

How would this look using Dataloader ?

This is from the schema definition:

alias App.Data

# ...

object :app do
  field :users, list_of(:user) do
    resolve fn app, _args, %{context: %{loader: loader}} ->

      params = [is_admin: true, group_id: [1,2,3]]

      loader
      |> Data.load_many(:users, params)
      |> on_load(fn loader ->
        {:ok, Data.get_many(loader, :user, params)}
      end)
    end
  end
end

and this is the data source module:

defmodule App.Data do
  alias App.User

  def data do
    Dataloader.Ecto.new(Repo, run_batch: &run_batch/5)
  end

  def load_many(loader, :users, [is_admin: is_admin, group_id: ids]) do
    Dataloader.load(loader, __MODULE__, {:many, {User, is_admin: is_admin}}, group_id: ids)
  end

  def get_many(loader, :users, [is_admin: is_admin, group_id: ids]) do
    Dataloader.load(loader, __MODULE__, {:many, {User, is_admin: is_admin}}, group_id: ids)
  end

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

Solution

  • So to answer my own question, the solution that worked was to leverage the &query/2 of Dataloader so the resolver in GQL resolver would basically look like this:

    loader
    |> Data.load({:many, User, group_ids: ids}, is_admin: true)
    |> on_load(fn loader ->
       loader
       |> Data.get({:many, User, group_ids: ids}, is_admin: true)
       # ...
    end)
    

    ... and the query/2 method in the App.Data module would look like this:

    defp query(User, %{group_ids: ids}) do
       from u in User, where: u.group_id in ^ids
    end
    

    This is explained here:

    https://hexdocs.pm/lazyloader/Dataloader.Ecto.html#module-filtering-ordering