AE
Ash Elixirβ€’3y ago
fekle

Conditional filters in read actions

Hi there, I'm back with another quesion that i couldnt find an answer to - sorry if i missed something. I have a resource with a list of form submissions, where i have a read action to get all form submission of a specific form id, with the form_id as an argument. that works fine. Now i also want to add the possibility to get all records submitted after a specific date, which also works this way: filter expr(submission_time >= ^arg(:min_submission_time)). Now, the :min_submission_time argument is optional - i want to be able to use the same action for getting both all as well as the filtered submissions. Is there a way to have a conditional in the action to only apply the :min_submission_time filter if the argument is not nil? As far as I know the action code is evaluated at compile time, so i cant use a normal elixir if/else. I am aware that i could just split this up into 2 different actions, but that would require duplicating things like the default sort order and filtering by form id. Thanks!
6 Replies
ZachDaniel
ZachDanielβ€’3y ago
You have to options πŸ™‚ the built in filter option is really just short hand for adding a custom preparation that filters.
prepare fn query, _ ->
if query.arguments[:submission_time] do
Ash.Query.filter(…)
else
query
end
end
prepare fn query, _ ->
if query.arguments[:submission_time] do
Ash.Query.filter(…)
else
query
end
end
The other option is that ash expressions support if
expr(
if ^arg(:min_submission_tjme) do
submission_time >= ^arg(:min_submission_time)
else
true
end
)
expr(
if ^arg(:min_submission_tjme) do
submission_time >= ^arg(:min_submission_time)
else
true
end
)
fekle
fekleOPβ€’3y ago
Thanks! I tried the second solution but found the following - if I keep the else true in it, then it seems to ignore other filters in the action - if i remove the else true then i always get 0 results thats how it looks now:
read :get_records do
argument :form_id, :integer do
allow_nil? false
end

argument :min_submission_time, :utc_datetime do
allow_nil? true
end

prepare build(sort: [submission_id: :desc])

filter expr(form_id == ^arg(:form_id))

filter expr(
if not is_nil(^arg(:min_submission_time)) do
submission_time >= ^arg(:min_submission_time)
else
true
end
)
end
read :get_records do
argument :form_id, :integer do
allow_nil? false
end

argument :min_submission_time, :utc_datetime do
allow_nil? true
end

prepare build(sort: [submission_id: :desc])

filter expr(form_id == ^arg(:form_id))

filter expr(
if not is_nil(^arg(:min_submission_time)) do
submission_time >= ^arg(:min_submission_time)
else
true
end
)
end
OK, my bad it always ignores the first filter - seems like i can only have one filter. I can combine both filters like this - is that the "idiomatic" syntax for this?
filter [
expr(form_id == ^arg(:form_id)),
expr(
if not is_nil(^arg(:min_submission_time)) do
submission_time >= ^arg(:min_submission_time)
else
true
end
)
]
filter [
expr(form_id == ^arg(:form_id)),
expr(
if not is_nil(^arg(:min_submission_time)) do
submission_time >= ^arg(:min_submission_time)
else
true
end
)
]
ZachDaniel
ZachDanielβ€’3y ago
Nope, that won’t work. That would always return everything. You’d combine them into a single expression with or Or and But yeah there can currently only be one filter. Many people have asked for there to be multiple so I should probably just do that today πŸ™‚
fekle
fekleOPβ€’3y ago
Well but when i think of it, if there are multiple filters then its unclear if they are AND or OR πŸ™‚ so there would need to be a new syntax so you mean like this?
filter expr(
expr(form_id == ^arg(:form_id)) and
expr(
if not is_nil(^arg(:min_submission_time)) do
submission_time >= ^arg(:min_submission_time)
else
true
end
)
)
filter expr(
expr(form_id == ^arg(:form_id)) and
expr(
if not is_nil(^arg(:min_submission_time)) do
submission_time >= ^arg(:min_submission_time)
else
true
end
)
)
cleaner like this, seems to work - thanks!! πŸ™‚
filter expr(
form_id == ^arg(:form_id) and
if not is_nil(^arg(:min_submission_time)) do
submission_time >= ^arg(:min_submission_time)
else
true
end
)
filter expr(
form_id == ^arg(:form_id) and
if not is_nil(^arg(:min_submission_time)) do
submission_time >= ^arg(:min_submission_time)
else
true
end
)
ZachDaniel
ZachDanielβ€’3y ago
filter expr(...)
filter expr(...)
filter expr(...)
filter expr(...)
when I support that, it will be and similarly to how calling query |> Ash.Query.filter(...) |> Ash.Query.filter(...) will use and but Yeah that looks great πŸ™‚
fekle
fekleOPβ€’3y ago
great, thanks again for your help!

Did you find this page helpful?