lardcanoe
I am trying to parse a user generated filter that will apply to jsonb field (that is just a map, not an embedded resource).
The field is data, and if I include it in the statement sent to parse_input I get an Ash.Error.Query.NoSuchFilterPredicate error.
If I exclude that field, and instead manually apply it, |> Ash.Query.filter(data[:size] == ^"Big") then things works.
Is there a syntax to allow passing fields of a map into the parse function? If not, how can I pass it to Ash.Query.filter? To make it slightly more complicated, I would also like to be able to filter on the data field when it is on a reference as well. e.g. `%{person: %{data: %{size: “Big”}}}
statement = %{
person: %{parent: %{name: "Daniels"}},
data: %{size: "Big"}
}
# This will blow up with the above
{:ok, filter} = Ash.Filter.parse_input(resource, statement)
# If I remove "data" and instead do it manually, then this works:
resource
|> Ash.Query.for_read(read_action, %{}, actor: actor, tenant: tenant)
|> Ash.Query.filter_input(filter)
|> Ash.Query.filter(data[:size] == ^"King")
Filtering on embedded resource? - #6 by zachdaniel was where I saw the Ash.Query.filter approach on arbitrary fields of a jsonb attribute; I just couldn’t figure out how to pass my user generated filter since that is a macro.
Thank you!
Trending in Questions
Other Trending Topics
Categories:
Sub Categories:
Forums
Popular Tags
- #ecto
- #liveview
- #troubleshooting
- #learning-elixir
- #deployment
- #library
- #erlang
- #testing
- #genserver
- #mix
- #absinthe
- #remote-other
- #otp
- #plug
- #how-to-question
- #macros
- #postgres
- #channels
- #elixirconf
- #exunit
- #discussion
- #code-sync
- #javascript
- #podcasts
- #onsite
- #dialyzer
- #docker
- #authentication
- #umbrella
- #full-time-contract
- #podcasts-by-brainlid
- #ecto-query
- #elixir-ls
- #blog-post
- #phoenix_html
- #iex
- #graphql
- #genstage
- #ai
- #elixirconf-us
- #websockets
- #supervisor
- #advent-of-code
- #distillery
- #processes
- #api
- #forms
- #metaprogramming
- #security
- #hex










First 10 of 10 Posts
zachdaniel
I think this is actually something missing from
Ash.Filter, specifically when given a nested map like that we should check for embedded resources and allow you to apply that kind of filter. Could you open an issue for it in Ash?Another way to achieve this kind of thing is to add calculations to the root resource, i.e
and then allow filtering on
:size. Not a feasible option for every case though.lardcanoe
Created Filter a map attribute using user input · Issue #862 · ash-project/ash · GitHub
The
sizefilter was just an example, it could be any field, and deeply nested. Basically, that data field maps to a JSON schema that is defined at runtime. I hacked together an approach using fragments that works fine until you join another table that also has adatafield, and postgres has the ambiguous error. I saw in another post using anas(0)notation, but that seems hokey for my case and also wasn’t sure how to in the fragment.There is no “hidden” method I can call that replicates what
Ash.Query.filter(data[:size] == ^"King")is doing? Because I am fine breaking out thedatafilters into another approach while keepingparse_inputfor the pre-defined attributes.zachdaniel
There are definitely ways to build the filter yourself and to dynamically build references that won’t bring on the ambiguous references that you mentioned, i.e a simplified thing
This can be adapted to support nested keys and to do things like
get_path(ref(^key), ^list_of_keys) == ^value).However, I’ve just pushed support for doing this automatically with non-array embedded types in input filters to
ashmain. Keep in mind there is still some experimental stuff inmain, and if you want to use it you should also upgradeash_postgresto latestmainas well.lardcanoe
You’re a machine!
What cup of coffee are you on?
I pulled main for ash and ash_postgres and it had the same error.
I think your new code worked because the attribute is defined as
attribute :embedded_bio, EmbeddedBioand notattribute :embedded_bio, :mapI hacked up my own embedded resource and attached it to my
datafield and the code works. But I need it for a generic:mapSorry for the bad news
I don’t want to abuse you, so I’ll reopen the github issue and get to it when you can. Thanks!
zachdaniel
Ah
so, this is a bit harder. The reason for that is that you can use a predicate 
%{data: %{eq: 10}}, and we can’t tell if you meandata.eq == 10ordata == 10. The format is, unfortunately, a bit ambiguous. We’d have to figure something else out to for this.EDIT: to make it clear, you can use all kinds of predicates, like
%{data: %{less_than: 10}}zachdaniel
I’m thinking what we need to do actually is walk back the previous change, and introduce a new syntax for including paths in input. Perhaps something like this:
zachdaniel
So, I made that change and realized that it just kind of shuffles the problem around, because if you have an attribute called
at_pathit would be problematic…but actually I think it’s fine. The reason its fine is thatat_pathexpects a list, and if you need to match on it you can sayat_path: %{eq: ["foo"]}, so there is an escape hatch (albeit a bit of a convoluted one)zachdaniel
Alright, I’ve pushed this change to
main(and removed the previous change I added)lardcanoe
(edit: replied before seeing your new change. let me do that first)
Can you see in the filter logic that
datais anAsh.Type.Mapso any condition being applied to it would actually be for fields in the map?For your example, I wasn’t sure how to use it.
Do you have a more complete example of using
Ash.Expr.exprbecause elixir ain’t happy with that. Can’t find key, value, expr.zachdaniel
This covers the case a little bit, but there can also be custom types that are backed by maps, and we can’t detect them all.
You need to
require Ash.ExprbecauseAsh.Expr.expris a macro.