I am using absinthe with elixir (phoenix 1.3). I have a blog app that has Users, Posts, and Likes, and the likes are joined with a many-to-many relationship between Users and Posts.
schema "users" do
field :email, :string
field :handle, :string
many_to_many :liked_posts, MyApp.Content.Post, join_through: "likes"
end
schema "posts" do
field :title, :string
field :content, :string
many_to_many :liking_users, MyApp.Accounts.User, join_through: "likes"
end
schema "likes" do
belongs_to :user, MyApp.Accounts.User
belongs_to :post, MyApp.Content.Post
end
Let's say I want to aggregate them on the backend rather than the front. I would like :liked_by
to simply be a count of all the likes that exist, more like field :likes, :int
, so that I can get back responses like this:
{
"data": {
"post" : {
"title" : "Title",
"content" : "This is the content",
"likes" : 7
}
}
}
What would my object have to look like? I want to do something like this:
object :post do
field :id, :integer
field :title, :string
field :content, :string
field :likes, :integer, resolve: assoc(:liking_users, fn query, id, _ ->
query |> from like in MyApp.Content.Like, where: like.post_id == ^id, select: count("*")
)
end
EDIT #1: More specifically, I'd like to know how to parameterize an anonymous function in the absinthe object. I can get the object to return a non-parameterized value easily:
field :somenumber, :integer, resolve: fn (_,_) -> {:ok, 15} end
But adding a parameter like so
field :somenumber, :integer, resolve: fn (foo,_) -> {:ok, foo} end
returns the following:
...
"somenumber": {},
...
How can I pass in id of the object, or an implicitly associated query?
EDIT #2: I have found a solution to this, but it feels very hacky.
object :post do
field :id, :integer
field :title, :string
field :content, :string
field :likes, :integer, resolve: fn (_,_,resolution) ->
{:ok, Post.getLikeCount(resolution.source.id) }
end
end
After following @mudasobwa's advice, I have this solution:
object :post do
field :id, :integer
field :title, :string
field :content, :string
field :likes, :integer, resolve: fn (query,_,_) ->
Post.getLikeCount(query.id)
end
end
resolution
, the third argument of the arity 3 anonymous function for the resolver, is an Absinthe.Resolution
object. resolution.source
is of type MyApp.Content.Post
, of which id
refers to that Post.
Then I just added a function into Post.ex called getLikeCount/1
that gets the number of likes.
def getLikeCount (post_id) do
query =
from l in MyApp.Content.Likes,
where: l.post_id == ^post_id,
select: count("*")
case Repo.one(query) do
nil -> {:error, "Error getting like count for post #{post_id}"}
likes -> {:ok, likes}
end
end