Skip to content

Instantly share code, notes, and snippets.

@Wigny
Created February 8, 2025 08:38
Show Gist options
  • Save Wigny/66c83d7fa3673eabee96982a86ae9372 to your computer and use it in GitHub Desktop.
Save Wigny/66c83d7fa3673eabee96982a86ae9372 to your computer and use it in GitHub Desktop.
Dataloader usage example
Mix.install([:dataloader])
defmodule User do
defstruct [:id, :name]
def list do
[
%__MODULE__{id: 1, name: "John"},
%__MODULE__{id: 2, name: "Alice"},
%__MODULE__{id: 3, name: "Bob"}
]
end
end
defmodule Post do
defstruct [:id, :user_id, :content]
def first, do: List.first(list())
def list do
[
%__MODULE__{id: 1, user_id: 1, content: "..."},
%__MODULE__{id: 2, user_id: 2, content: "..."},
%__MODULE__{id: 3, user_id: 3, content: "..."}
]
end
end
defmodule Comment do
defstruct [:user_id, :post_id, :message]
def list(filter \\ %{}) do
for comment <- [
%__MODULE__{post_id: 1, user_id: 2, message: "..."},
%__MODULE__{post_id: 1, user_id: 2, message: "..."},
%__MODULE__{post_id: 1, user_id: 3, message: "..."},
%__MODULE__{post_id: 2, user_id: 1, message: "..."},
%__MODULE__{post_id: 3, user_id: 2, message: "..."}
],
Map.take(comment, Map.keys(filter)) == filter,
do: comment
end
end
defmodule DataSource do
def new do
Dataloader.KV.new(&load/2)
end
defp load(:comments, posts) do
Map.new(posts, fn %Post{} = post ->
comments = Comment.list(%{post_id: post.id})
{post, comments}
end)
end
defp load({:comments, %{user: user}}, posts) do
Map.new(posts, fn %Post{} = post ->
comments = Comment.list(%{post_id: post.id, user_id: user.id})
{post, comments}
end)
end
defp load(:commenters, posts) do
Map.new(posts, fn %Post{} = post ->
comments = Comment.list(%{post_id: post.id})
commenters_id = Enum.map(comments, & &1.user_id)
commenters = Enum.filter(User.list(), &(&1.id in commenters_id))
{post, commenters}
end)
end
end
ExUnit.start()
ExUnit.run()
defmodule Test do
use ExUnit.Case, async: true
test "load comments post" do
post = Post.first()
loader = Dataloader.add_source(Dataloader.new(), :example, DataSource.new())
loader = Dataloader.load(loader, :example, :comments, post)
loader = Dataloader.run(loader)
comments = Dataloader.get(loader, :example, :comments, post)
assert comments == [
%Comment{post_id: post.id, user_id: 2, message: "..."},
%Comment{post_id: post.id, user_id: 2, message: "..."},
%Comment{post_id: post.id, user_id: 3, message: "..."}
]
end
test "load user comments on post" do
user = %User{id: 2}
post = Post.first()
loader = Dataloader.add_source(Dataloader.new(), :example, DataSource.new())
loader = Dataloader.load(loader, :example, {:comments, %{user: user}}, post)
loader = Dataloader.run(loader)
comments = Dataloader.get(loader, :example, {:comments, %{user: user}}, post)
assert comments == [
%Comment{post_id: post.id, user_id: user.id, message: "..."},
%Comment{post_id: post.id, user_id: user.id, message: "..."}
]
end
test "load user comments on many posts" do
user = %User{id: 2}
posts = Post.list()
loader = Dataloader.add_source(Dataloader.new(), :example, DataSource.new())
loader = Dataloader.load_many(loader, :example, {:comments, %{user: user}}, posts)
loader = Dataloader.run(loader)
posts_comments = Dataloader.get_many(loader, :example, {:comments, %{user: user}}, posts)
assert posts_comments == [
[
%Comment{post_id: 1, user_id: 2, message: "..."},
%Comment{post_id: 1, user_id: 2, message: "..."}
],
[],
[
%Comment{post_id: 3, user_id: 2, message: "..."}
]
]
last_post_comments =
Dataloader.get(loader, :example, {:comments, %{user: user}}, List.last(posts))
assert last_post_comments == [
%Comment{post_id: 3, user_id: 2, message: "..."}
]
end
test "load commenters of post" do
[post1, post2, post3] = Post.list()
loader = Dataloader.add_source(Dataloader.new(), :example, DataSource.new())
loader = Dataloader.load_many(loader, :example, :commenters, [post1, post2, post3])
loader = Dataloader.run(loader)
assert Dataloader.get(loader, :example, :commenters, post1) == [
%User{id: 2, name: "Alice"},
%User{id: 3, name: "Bob"}
]
assert Dataloader.get(loader, :example, :commenters, post2) == [
%User{id: 1, name: "John"}
]
assert Dataloader.get(loader, :example, :commenters, post3) == [
%User{id: 2, name: "Alice"}
]
end
end
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment