absinthe-graphql / absinthe

The GraphQL toolkit for Elixir
http://absinthe-graphql.org
Other
4.29k stars 527 forks source link

Possible Bug in dataloader resolution helper when parent Id is null #1316

Closed arunr14 closed 6 months ago

arunr14 commented 6 months ago

I am unsure if this an issue in the Absinthe resolver helper code or the underlying Dataloader.get code. Apologies if posting in the wrong place. The summary is that the dataloader/1 resolver gets an incorrect object when the parent 's primary key is null

Environment

Expected behavior

We have a object called once_task that has a field called patient. This field is resolved using dataloader/1. We have run into an issue where the resolved patient is incorrect when the once_task primary key (Id) is null. Note that the task id being null is a valid use case for us and other fields are not null including the foreign key patient_id

The work around for this issue is the specify the batch key and the foreign in the resolver. See code section for more details on workaround

Actual behavior

Incorrect patient object is added to once Task

Relevant Schema/Middleware Code

field :once_tasks, non_null_list(:once_task) do
      resolve &Queries.list_once_tasks/3
    end

NOTE : Queries.list_once_tasks does some custom logic and can return once_task with the primary key (id) as null


object :once_task do
    ecto_fields Tasks.OnceTask
    field :checklist, :checklist, resolve: dataloader(Tasks)
  end

When once tasks are queried, and the result has once_task.id as null, the patient field is associated incorrectly. I.e onceTask.patient_Id != onceTask.Patient.Id when once_task.id = null

We are able to work around this issue by using this resolver


object :once_task do
    ecto_fields Tasks.OnceTask
    field :checklist, :checklist, resolve: fn parent, _, %{context: %{loader: loader}} -> 
      loader
      |> Dataloader.load(Tasks, {:one, Tasks.Checklist}, id: parent.checklist_id)
      |> on_load(fn loader ->
        loader
        |> Dataloader.get(Tasks, {:one, Tasks.Checklist}, id: parent.checklist_id)
        |> (&{:ok, &1}).()
      end)
    end
  end
benwilson512 commented 6 months ago

Hey @arunr14 ecto related lookups are indeed the job of Dataloader, not Absinthe. Can you post an issue there, with a reproducible example?