How do I query a many-to-many relationship the Ecto way

Hello peeps, I feel this query isn’t concise (or isn’t Ecto-y) enough:

def list_posts_for(tag_id) do
  query =
    from(pt in PostTag,
      where: pt.tag_id == ^tag_id,
      left_join: p in Post,
      on: p.id == pt.post_id,
      select: p
    )

  Repo.all(query)
end

Posts and tags have many to many relationships + a join schema, and Ecto knows all about them.

Is it possible to start the query with from p in Post? Other ideas are welcome too.

Yes, you can.

Query post with id, and preload tags:

from p in Post, 
  join: t in assoc(p, :tags), 
  where: p.id == 1,
  preload: [tags: p]

But, personally, I would like to use preload directly:

Repo.get(Post, 1) |> Repo.preload(:tags)

If you need tags associated with a post only, try Ecto.assoc/2.