Skip to content

Instantly share code, notes, and snippets.

@smoak
Last active November 16, 2017 03:38
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 1 You must be signed in to fork a gist
  • Save smoak/e24b6774d48515d9fa0fd2c94d712bd1 to your computer and use it in GitHub Desktop.
Save smoak/e24b6774d48515d9fa0fd2c94d712bd1 to your computer and use it in GitHub Desktop.
defmodule ApiWeb.Schema do
use Absinthe.Schema
import Absinthe.Resolution.Helpers
import_types Absinthe.Type.Custom
@desc "A user"
object :user do
field :id, non_null(:string)
field :email, non_null(:string)
end
query do
@desc "Get a user given its id"
field :user, :user do
arg :id, non_null(:string)
resolve dataloader(:user)
end
end
def context(ctx) do
loader =
Dataloader.new
|> Dataloader.add_source(:user, Api.Loaders.Users.data())
Map.put(ctx, :loader, loader)
end
def plugins do
[Absinthe.Middleware.Dataloader] ++ Absinthe.Plugin.defaults()
end
end
defmodule Api.Loaders.Users do
def data() do
Dataloader.KV.new(&load/2)
end
def load(batch_key, ids) do
# if we made it this far, we haven't fetched before...
# this should return a tuple of
# {id, obj}
# batch_key is {:user, %{id: "1"}}
# ids is [%{}]
%{}
end
end
@bruce
Copy link

bruce commented Nov 14, 2017

Here's a working example:

In schema.ex (note the different name app module name):

defmodule ApiWeb.Schema do
  use Absinthe.Schema

  import Absinthe.Resolution.Helpers
  alias Api.Loaders

  import_types Absinthe.Type.Custom

  @desc "A user"
  object :user do
    field :id, non_null(:string)
    field :email, non_null(:string)
  end

  query do
    @desc "Get a user given its id"
    field :user, :user do
      arg :id, non_null(:string) # should probably be :id type
      resolve load(:user)
    end
  end

  def context(ctx) do
    Map.put(ctx, :loader, loader())
  end

  def plugins do
    [Absinthe.Middleware.Dataloader] ++ Absinthe.Plugin.defaults()
  end

  # Build the dataloader
  defp loader() do
    Dataloader.new
    |> Dataloader.add_source(:user, Loaders.Users.source())
  end

  # Reusable dataloader helper replacement for simple KV use.
  #
  # This serves the same purpose as the `dataloader` helper, but
  # as that's currently focused on batching by parent (object) for Ecto,
  # we (currently) need to do some special handling.
  def load(source_name) do
    fn _, args, %{context: %{loader: loader}} ->
      # The `nil` values here is the batch key; all batching
      # for the source automatically done together.
      loader
      |> Dataloader.load(source_name, nil, args)
      |> on_load(fn loader ->
        {:ok, Dataloader.get(loader, source_name, nil, args)}
      end)
    end
  end

end

In loaders/users.ex:

defmodule Api.Loaders.Users do

  def source() do
    Dataloader.KV.new(&fetch/2)
  end

  # The value of `batch_key` is unimportant; users are batched
  # together.
  #
  # `arg_maps` is synonymous with "ids", you're just using
  # each arg map as the item id,
  defp fetch(_batch_key, arg_maps) do
    IO.inspect(arg_maps: arg_maps)
    # Must return a map keyed by the arg maps, not just the
    # id values.
    %{}
  end

end

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment