tellesleandro

tellesleandro

How to compose queries?

Ecto allows to compose a query, like this:

def for_patio(query \\ __MODULE__, %Patio{} = patio) do
  query
  |> join(:inner, [pe], _ in assoc(pe, :patios), as: :patios)
  |> where([patios: p], p.id == ^patio.id)
end

def for_parceiro(query \\ __MODULE__, %Parceiro{} = parceiro, voucher) do
  query
  |> join(:inner, [pe], ape in assoc(pe, :parceiros_precos_estadias),
    as: :parceiros_precos_estadias
  )
  |> where(
    [parceiros_precos_estadias: ape],
    ape.parceiro_id == ^parceiro.id and
      ape.voucher == ^voucher
  )
end

I can query the resource in different ways:

  • Resource.for_patio(patio) |> Repo.all
  • Resource.for_parceiro(parceiro, voucher) |> Repo.all
  • Resource.for_patio(patio) |> Resource.for_parceiro(parceiro, voucher) |> Repo.all

How do I do that using Ash?

Marked As Solved

zachdaniel

zachdaniel

Creator of Ash

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.

Also Liked

zachdaniel

zachdaniel

Creator of Ash

No problem :slight_smile: I appreciate your questions, and I while we definitely want to improve the documentation, having these kinds of questions here in the forum will help other people when they have similar questions. Documentation improvements are a longer term type thing, but this will help people in the short term :slight_smile:

yasoob

yasoob

Hey @tellesleandro i just wanna say that your questions and the ensuing discussion is very helpful for newbies like me. Thanks for asking these questions! :grin:

zachdaniel

zachdaniel

Creator of Ash

You’d use calculations for this:

calculations do
  calculate :for_patio, :boolean, expr(exists(patios, id == ^arg(:id)) do
    argument :id, :uuid, allow_nil?: false
  end

  calculate :for_parceiro, :boolean, expr(exists(parceiros_precos_estadias, parceiro_id == ^arg(:parceiro_id) and voucher == ^arg(:voucher)))
end

And then you can query like

query =
  Resource
  |> Ash.Query.filter(for_parceiro(parceiro_id: parceiro_id, voucher: voucher))

# or 

query =
  Resource
  |> Ash.Query.filter(for_patio(patio_id: patio_id))

# or combine them

query =
  Resource
  |> Ash.Query.filter(for_parceiro(parceiro_id: parceiro_id, voucher: voucher) and for_patio(patio_id: patio_id))

# they can also be combined in ways you can't combine your example

query =
  Resource
  |> Ash.Query.filter(for_parceiro(parceiro_id: parceiro_id, voucher: voucher) or for_patio(patio_id: patio_id))

You cold then call a code interface and provide this query

YourResource.read(..., query: query)

Or use the underlying api for it

YourResource
|> Ash.Query.filter(....)
|> YourApi.read!()

Where Next?

Popular in Questions Top

jaysoifer
Is there a way to rollback a specific migration and only that one (“skipping” all the other ones)? Would mix ecto.rollback -v 200809061...
New
lucidguppy
I have a super simple question about elixir - how would I take a file like this foo bar baz and output a new file that enumerates th...
New
hariharasudhan94
Lets say I have map like this fetching from my database %{"_id" => #BSON.ObjectId<58eb1a7a9ad169198c3dXXXX>, "email" => ...
New
ovidiubadita
Hey all, I discovered Elixir and I love it. I always wanted to learn a functional programming and I intended to go for Haskell, but afte...
New
mcarvalho
What is the difference between System.get_env and Application.get_env? For example, what are best practices to use one versus another.
New
Darmani72
If I have a post route which an argument: post /my_post_route/:my_param1, MyController.my_post_handler How would get the post params ...
New
9mm
I am constructing a JSON object (map) and I need to conditionally set a field. I’m trying to write proper elixir-way code… and I’m at a l...
New
sergio_101
I am VERY much an elixir newbie. I have taken one elixir course and one phoenix course on Udemy. During that course, I saw the instructor...
New
vrod
I am using the Starship cross-shell prompt – it seems pretty nice, but I get some errors: [WARN] - (starship::utils): Executing command ...
New
jason.o
In the code below, if the create action is not set to accept “extra_key” as an input, it errors out with a message shown above. Is there ...
New

Other popular topics Top

electic
Hi, I am new to Elixir. I am trying to use the DateTime component to insert a date into MySQL however the there seems to be no way to fo...
New
RisingFromAshes
I’ve read in another post that it may be possible with a router helper - but I couldn’t find an appropriate one, and tbh, I’m still just ...
New
josevalim
Hi everyone, One of the features added to Elixir early on to help integration with Erlang code was the idea of overridable function defi...
New
dokuzbir
I want to highlight html closing tags when i click a html tag. That works in .html files but doesnt work for html.eex templates. How can...
New
sorentwo
Hello! tl;dr Announcing Oban, an Ecto based job processing library with a focus on reliability and historical observability. After spen...
985 43487 311
New
jerry
Good day to you all. I have been struggling to get a query involving like and ilike to work. Can anyone assist me on this, please? pro...
New
pmjoe
I have a relationship of love and hate with Elixir. Lots of things are just absolutely right, but there are some things that are kind of ...
New
SoCreat
i’m a new one to elixir which editor can i use vs code? or atom? Thanks! :smiley:
New
WestKeys
Currently suffering from paralysis by [HTTP client] analysis. This is rather unusual in Elixirland as there tends to be consensus on the ...
New
jason.o
In the code below, if the create action is not set to accept “extra_key” as an input, it errors out with a message shown above. Is there ...
New

Latest on Elixir Forum

We're in Beta

About us Mission Statement