How to compose queries?

Honestly it just depends on how you’re using it. For instance, if you’ve got a live view somewhere, you can do this:

assign(socket, :published_posts, Post.published!())

But you can also do

assign(socket, :published_posts, Post.read!(query: Ash.Query.filter(published == true))

If you are considering making a module somewhere with functions like:

def published_posts do
  Post.read!(query: Ash.Query.filter(published == true)
end

Then at that point I would suggest making it an action, i.e

read :published do
  filter expr(published == true)
end

If you need caller-level composition, then calculations are a good choice.

I know it would be nice if there was “one right answer” but in these case it often comes down to what kind of interface you would need. The general rule of thumb though is: when in doubt, put stuff in an action that does specifically what you need.