Hey! This is totally doable. The main thing to note is fundamentally,
{
teachingCenters {
id
name
email
works in exactly the same way as
courses(search: "first") {
id
name
cycle
When you have teachingCenters
, you have the root query object, and you’re resolving a field for it, and you have a resolver.
When you do the courses
field it’s the same idea, you’re just resolving off of the teaching_center
object. The very naive version is basically:
object :teaching_center do
field :id, :id
# other fields
field :courses, list_of(:course) do
arg :search, :string
resolve fn teaching_center, args, _ ->
courses =
teaching_center
|> Ecto.assoc(:courses)
|> where(^args)
|> Repo.all
{:ok,
end
end
end
The idea is that when the query executor hits the courses
field, it just gets the teaching center it’s under, and runs a query.
I called it naive because of course when you have a list of teaching centers, this produces N + 1 queries, which is very bad. Fortunately, Absinthe has a middleware pattern from which batching can be constructed, and the Absinthe.Ecto project provides some handy functions for doing ecto based batching. With that in mind we can do something like:
object :teaching_center do
field :id, :id
# other fields
field :courses, list_of(:course) do
arg :search, :string
resolve assoc(:courses, fn courses_query, args, _ ->
posts_query |> where(^args) # or whatever
end)
end
end
Now it’ll do just 1 SQL query to grab all the courses, with whatever arg processing you have.
To make it nest further, just add resolvers to each of the fields that you want to be able to load data from.