diff --git a/lib/dataloader/ecto.ex b/lib/dataloader/ecto.ex index 27d393a..bb73f24 100644 --- a/lib/dataloader/ecto.ex +++ b/lib/dataloader/ecto.ex @@ -326,7 +326,11 @@ if Code.ensure_loaded?(Ecto) do defp chase_down_queryable([field | fields], schema) do case schema.__schema__(:association, field) do %{queryable: queryable} -> - chase_down_queryable(fields, queryable) + chase_down_queryable(fields, queryable) + + %Ecto.Association.HasThrough{through: [through_field | through_fields]} -> + [through_field | through_fields ++ fields] + |> chase_down_queryable(schema) end end diff --git a/priv/test_repo/migrations/1_migrate_all.exs b/priv/test_repo/migrations/1_migrate_all.exs index bbdd097..5ea1528 100644 --- a/priv/test_repo/migrations/1_migrate_all.exs +++ b/priv/test_repo/migrations/1_migrate_all.exs @@ -2,8 +2,13 @@ defmodule Absinthe.Ecto.TestRepo.Migrations.MigrateAll do use Ecto.Migration def change do + create table(:leaderboards) do + add :name, :string + end + create table(:users) do add :username, :string + add :leaderboard_id, references(:leaderboards) end create table(:posts) do @@ -16,5 +21,10 @@ defmodule Absinthe.Ecto.TestRepo.Migrations.MigrateAll do add :user_id, references(:users), null: false add :post_id, references(:posts), null: false end + + create table(:scores) do + add :leaderboard_id, references(:leaderboards), null: false + add :post_id, references(:posts), null: false + end end end diff --git a/test/dataloader/ecto_test.exs b/test/dataloader/ecto_test.exs index 999a118..1f91808 100644 --- a/test/dataloader/ecto_test.exs +++ b/test/dataloader/ecto_test.exs @@ -1,7 +1,7 @@ defmodule Dataloader.EctoTest do use ExUnit.Case, async: true - alias Dataloader.{User, Post, Like} + alias Dataloader.{User, Post, Like, Score, Leaderboard} import Ecto.Query alias Dataloader.TestRepo, as: Repo @@ -291,6 +291,33 @@ defmodule Dataloader.EctoTest do assert length(loaded_posts) == 2 end + test "works with nested has many through", %{loader: loader} do + leaderboard = %Leaderboard{name: "Bestliked"} |> Repo.insert!() + user = %User{username: "Ben Wilson", leaderboard_id: leaderboard.id} |> Repo.insert!() + + post = %Post{user_id: user.id} |> Repo.insert!() + _score = %Score{post_id: post.id, leaderboard_id: leaderboard.id} |> Repo.insert!() + _like1 = %Like{post_id: post.id, user_id: user.id} |> Repo.insert!() + _like2 = %Like{post_id: post.id, user_id: user.id} |> Repo.insert!() + + loader = + loader + |> Dataloader.load(Test, :awarded_posts, user) + |> Dataloader.load(Test, :likes, user) + |> Dataloader.run() + + loaded_posts = + loader + |> Dataloader.get(Test, :awarded_posts, user) + loaded_likes = + loader + |> Dataloader.get(Test, :likes, user) + + + assert length(loaded_posts) == 1 + assert length(loaded_likes) == 2 + end + test "preloads aren't used", %{loader: loader} do user = %User{username: "Ben Wilson"} |> Repo.insert!() diff --git a/test/support/leaderboard.ex b/test/support/leaderboard.ex new file mode 100644 index 0000000..4a1556b --- /dev/null +++ b/test/support/leaderboard.ex @@ -0,0 +1,8 @@ +defmodule Dataloader.Leaderboard do + use Ecto.Schema + + schema "leaderboards" do + field(:name, :string) + has_many(:scores, Dataloader.Score) + end +end diff --git a/test/support/score.ex b/test/support/score.ex new file mode 100644 index 0000000..ad87040 --- /dev/null +++ b/test/support/score.ex @@ -0,0 +1,8 @@ +defmodule Dataloader.Score do + use Ecto.Schema + + schema "scores" do + belongs_to(:post, Dataloader.Post) + belongs_to(:leaderboard, Dataloader.Leaderboard) + end +end diff --git a/test/support/user.ex b/test/support/user.ex index ff2821b..2f6b326 100644 --- a/test/support/user.ex +++ b/test/support/user.ex @@ -4,5 +4,10 @@ defmodule Dataloader.User do schema "users" do field(:username, :string) has_many(:posts, Dataloader.Post) + belongs_to(:leaderboard, Dataloader.Leaderboard) + + has_many(:scores, through: [:leaderboard, :scores]) + has_many(:awarded_posts, through: [:scores, :post]) + has_many(:likes, through: [:awarded_posts, :likes]) end end