absinthe-graphql / absinthe_ecto

DEPRECATED: Use dataloader
MIT License
130 stars 36 forks source link

Fetch Single Record #27

Closed maxsalven closed 7 years ago

maxsalven commented 7 years ago

Lets say an event has many attendees (events_users), and we have a unique index so that a user can't attend the same event twice.

Is there a way using absinthe_ecto to have a field on event called e.g. current_user_attendance which checks if the current user attended the event, but instead of returning a list with a single 'attendance', it returns the field directly?

  object :event do
    field :current_user_attendance, list_of(:event_user) do
      resolve assoc(:events_users, fn query, args, %{current_user: current_user} ->
        query
        |> where([eu], eu.user_id == ^current_user.id)
      end)
    end
  end

The above works fine, except it'll return the aforementioned list, when we know be definition there will be either one or zero results.

I appreciate I could write a custom resolver, but it would be very elegant to do it in absinthe_ecto, as when you're fetching many events it very cleanly takes care of n+1 issues.

benwilson512 commented 7 years ago

Hey! Presumably then the :events_users relation is a has many, so yeah by default it'll come back as a list. However, we can use assoc/4 to get a callback after the record is loaded, to unwrap the item.

https://hexdocs.pm/absinthe_ecto/Absinthe.Ecto.html#assoc/4

resolve assoc(MyApp.Repo, :events_users, &scope/3, &unwrap/1)

defp scope(query, args, %{current_user: current_user}) do
  query
  |> where([eu], eu.user_id == ^current_user.id)
end

defp unwrap([event]), do: {:ok, event}
defp unwrap([]),      do: {:ok, nil}
maxsalven commented 7 years ago

Fantastic, thank you.

I notice I have to explicitly import or alias Absinthe.Ecto to use assoc/4, any plans to allow access via the use Absinthe.Ecto, repo: MyApp.Repo macro?

benwilson512 commented 7 years ago

No, I'm generally not a fan of use invocations that also import, particularly if they import commonly used functions. assoc also exists in Ecto and can in certain situations break ecto queries if it's automatically imported.

maxsalven commented 7 years ago

Would it not bring things more inline with the assoc syntax in the rest of Absinthe? field :user, :user, resolve: assoc(:user)

field :users, list_of(:user) do
   resolve assoc(:users, fn query, args, ...
benwilson512 commented 7 years ago

Ah sorry what I'm trying to say is that it may have been a mistake to auto-import anything at all, and there's a good chance in the next version nothing will be imported by default.

The question is a bit moot however because Absinthe 1.4.0 is positioning to promote https://github.com/CargoSense/data_loader over absinthe_ecto.

maxsalven commented 7 years ago

Understood, thank you. Will take a look at the data_loader.

benwilson512 commented 7 years ago

Docs and so on are still forthcoming, but it should all show up in the next book chapter that'll be out soon.