1

In my phoenix application, I have a many to many relationship between an Artist and a Cause schema implemented using a join table artists_causes. In my Artist schema, I have many_to_many :causes, Cause, join_through: "artists_causes" and in the Cause schema I have many_to_many :artists, Artist, join_through: "artists_causes" I am using absinthe for graphql and in my CauseTypes module, I have implemented a the cause object as below

defmodule MyAppWeb.Schema.CauseTypes do
  @moduledoc """
  All types for causes
  """
  use Absinthe.Schema.Notation
  import Absinthe.Resolution.Helpers, only: [dataloader: 1, dataloader: 3]

  object :cause do
    field :id, :id
    field :artists, list_of(:artist), resolve: dataloader(Artists)
  end

  def dataloader do
    alias MyApp.{Artists, Causes}
    loader = Dataloader.new
    |> Dataloader.add_source(Causes, Causes.datasource())
    |> Dataloader.add_source(Artists, Artists.datasource())
  end

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

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

From my understanding, with Absinthe Dataloader, the dataloader/1 is what I need to have the list of Artists loaded. However, I am not able to query for the artists from within a cause getting the error artists: #Ecto.Association.NotLoaded<association :artists is not loaded> when I run the query below in graphiql

query{
 causes{
  id
  artists {
            id
   }
 }
}

Is there any little piece that I am missing on working with many to many relationships?

==========

Update

I updated my list_causes function as below

def list_causes do    
   Repo.all(MyApp.Causes.Cause) 
end

to

def list_causes do
    Repo.all(from c in Cause,
    left_join: ac in "artists_causes", on: c.id == ac.cause_id,
    left_join: a in Artist, on: a.id == ac.artist_id,
    preload: [:artists]
    )
  end

and , I am now getting the error FunctionClauseError at POST /graphiql\n\nException:\n\n ** (FunctionClauseError) no function clause matching in anonymous fn/3 in Absinthe.Resolution.Helpers.dataloader/1 which maybe pointing towards with the Absinthe.Resolution.Helpers.dataloader/1 method. I have the helpers imported Is there something else I could be missing?

Mike Aono
  • 859
  • 2
  • 11
  • 17

1 Answers1

0

I think you must preload relation with artists manualy from Ecto, before passing it to Absinthe.

For example, fetch causes like:

from(c in Cause,
  preload: [:artists],
  select: c
)
|> Repo.all()

ADDITIONAL

My way of resolving Absinthe query.

In query object I pass resolver module function reference.

resolve(&App.Resolver.get_all_causes/2)

And with resolver function I return dataset

def get_all_causes(_params, _info) do
  {:ok,
   from(c in Cause,
     preload: [:artists],
     select: c
   )
   |> Repo.all()}
end
  • Hi @TreeFolk thanks, I have updated as you suggested and now am getting the error `(FunctionClauseError) no function clause matching in anonymous fn/3 in Absinthe.Resolution.Helpers.dataloader/1` which could be pointing to something with the ResolutionHelpers, could there be something I am missing? – Mike Aono Oct 16 '19 at 19:32
  • Unfortunately I based my answer on my own experience with Absinthe and I did not use Dataloader. I will add example of my solution. – Konrad Słotwiński Oct 17 '19 at 08:39