Skip to content

Commit

Permalink
Add missing test cases for has_many
Browse files Browse the repository at this point in the history
  • Loading branch information
jadlr committed Mar 10, 2021
1 parent f52daa2 commit 35bbe2f
Show file tree
Hide file tree
Showing 5 changed files with 84 additions and 2 deletions.
32 changes: 32 additions & 0 deletions lib/dataloader/ecto.ex
Original file line number Diff line number Diff line change
Expand Up @@ -872,6 +872,21 @@ if Code.ensure_loaded?(Ecto) do
build_preload_lateral_query(rest, query, :join_last)
end

defp build_preload_lateral_query(
[%Ecto.Association.Has{} = assoc | rest],
query,
:join_first
) do
query =
query
|> join(:inner, [x], y in ^assoc.owner,
on: field(x, ^assoc.related_key) == field(y, ^assoc.owner_key)
)
|> Ecto.Association.combine_joins_query(assoc.where, 0)

build_preload_lateral_query(rest, query, :join_last)
end

defp build_preload_lateral_query([assoc | rest], query, :join_first) do
query =
query
Expand All @@ -882,6 +897,23 @@ if Code.ensure_loaded?(Ecto) do
build_preload_lateral_query(rest, query, :join_last)
end

defp build_preload_lateral_query(
[%Ecto.Association.Has{} = assoc | rest],
query,
:join_last
) do
binds_count = Ecto.Query.Builder.count_binds(query)

join_query =
query
|> Ecto.Association.combine_joins_query(assoc.where, binds_count - 1)
|> join(:inner, [..., x], y in ^assoc.owner,
on: field(x, ^assoc.related_key) == field(y, ^assoc.owner_key)
)

build_preload_lateral_query(rest, join_query, :join_last)
end

defp build_preload_lateral_query([assoc | rest], query, :join_last) do
query =
query
Expand Down
50 changes: 48 additions & 2 deletions test/dataloader/ecto/has_many_where_test.exs
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
defmodule Dataloader.Ecto.HasManyWhereTest do
use ExUnit.Case, async: true

alias Dataloader.{User, Post, Like}
alias Dataloader.{User, Post, Like, Picture, UserPicture}
import Ecto.Query
alias Dataloader.TestRepo, as: Repo

Expand Down Expand Up @@ -47,7 +47,7 @@ defmodule Dataloader.Ecto.HasManyWhereTest do
assert [post1] == Dataloader.get(loader, Test, args, user1)
end

test "simple filtered has_many in has_many through in first position", %{loader: loader} do
test "filtered has_many in has_many through in first position", %{loader: loader} do
user1 = %User{username: "Ben Wilson"} |> Repo.insert!()

post1 = %Post{user_id: user1.id, title: "foo", status: "published"} |> Repo.insert!()
Expand All @@ -65,5 +65,51 @@ defmodule Dataloader.Ecto.HasManyWhereTest do

assert [like1] == Dataloader.get(loader, Test, args, user1)
end

test "filtered has_many in has_many through in second position", %{loader: loader} do
user1 = %User{username: "Ben Wilson"} |> Repo.insert!()

pic1 = %Picture{url: "https://example.com/1.jpg"} |> Repo.insert!()
pic2 = %Picture{url: "https://example.com/2.jpg"} |> Repo.insert!()

%UserPicture{user_id: user1.id, picture_id: pic1.id} |> Repo.insert!()
%UserPicture{user_id: user1.id, picture_id: pic2.id} |> Repo.insert!()

like1 = %Like{user_id: user1.id, picture_id: pic1.id, status: "published"} |> Repo.insert!()

_like2 =
%Like{user_id: user1.id, picture_id: pic2.id, status: "unpublished"} |> Repo.insert!()

args = {:published_picture_likes, %{limit: 10}}

loader =
loader
|> Dataloader.load(Test, args, user1)
|> Dataloader.run()

assert [like1] == Dataloader.get(loader, Test, args, user1)
end

test "filtered has_many in has_many through in sandwich position", %{loader: loader} do
leaderboard = %Dataloader.Leaderboard{name: "Top Bloggers"} |> Repo.insert!()
user1 = %User{username: "Ben Wilson", leaderboard_id: leaderboard.id} |> Repo.insert!()

post1 = %Post{user_id: user1.id, title: "foo", status: "published"} |> Repo.insert!()
post2 = %Post{user_id: user1.id, title: "bar", status: "unpublished"} |> Repo.insert!()

like1 = %Like{user_id: user1.id, post_id: post1.id} |> Repo.insert!()

_like2 =
%Like{user_id: user1.id, post_id: post2.id, status: "unpublished"} |> Repo.insert!()

args = {:user_published_posts_likes, %{limit: 10}}

loader =
loader
|> Dataloader.load(Test, args, leaderboard)
|> Dataloader.run()

assert [like1] == Dataloader.get(loader, Test, args, leaderboard)
end
end
end
1 change: 1 addition & 0 deletions test/support/leaderboard.ex
Original file line number Diff line number Diff line change
Expand Up @@ -9,5 +9,6 @@ defmodule Dataloader.Leaderboard do
has_many(:user_pictures_published, through: [:users, :pictures_published])
has_many(:user_pictures_likes, through: [:users, :pictures, :likes])
has_many(:user_pictures_published_likes, through: [:users, :pictures_published, :likes])
has_many(:user_published_posts_likes, through: [:users, :published_posts, :likes])
end
end
1 change: 1 addition & 0 deletions test/support/picture.ex
Original file line number Diff line number Diff line change
Expand Up @@ -5,5 +5,6 @@ defmodule Dataloader.Picture do
field(:status, :string)
field(:url, :string, null: false)
has_many(:likes, Dataloader.Like)
has_many(:published_likes, Dataloader.Like, where: [status: "published"])
end
end
2 changes: 2 additions & 0 deletions test/support/user.ex
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,8 @@ defmodule Dataloader.User do

many_to_many(:pictures, Dataloader.Picture, join_through: Dataloader.UserPicture)

has_many(:published_picture_likes, through: [:pictures, :published_likes])

many_to_many(:pictures_published, Dataloader.Picture,
join_through: Dataloader.UserPicture,
join_where: [status: "published"],
Expand Down

0 comments on commit 35bbe2f

Please sign in to comment.