Invalid Filter Reference

I'm getting an Ash.Error.Query.InvalidFilterReference I'm trying to push a particular filter into the DB level. I have this calculation, which works:
#issue.ex
calculate :has_sitewide_approved_match?,
:boolean,
expr(
exists(
scan.page.site.approved_issues,
rule_id == parent(rule_id) and
target == parent(target)
)
)
#issue.ex
calculate :has_sitewide_approved_match?,
:boolean,
expr(
exists(
scan.page.site.approved_issues,
rule_id == parent(rule_id) and
target == parent(target)
)
)
But when I try to use this in a filter expr(...) on its parent relationship (a scan has many issues), I get an invalid filter reference error:
#scan.ex
has_many :unapproved_node_issues, NodeIssue do
public? true
filter expr(has_sitewide_approved_match? != true)
end
#scan.ex
has_many :unapproved_node_issues, NodeIssue do
public? true
filter expr(has_sitewide_approved_match? != true)
end
The specific error is:
* ** (MatchError) no match of right hand side value: {:error, [%Ash.Error.Query.InvalidFilterReference{field: :target, simple_equality?: nil, splode: Ash.Error, bread_crumbs: [], vars: [], path: [:filter], stacktrace: #Splode.Stacktrace<>, class: :invalid}]}
* ** (MatchError) no match of right hand side value: {:error, [%Ash.Error.Query.InvalidFilterReference{field: :target, simple_equality?: nil, splode: Ash.Error, bread_crumbs: [], vars: [], path: [:filter], stacktrace: #Splode.Stacktrace<>, class: :invalid}]}
:target is just a simple string attribute. Is it not possible to do what I'm trying to do? Halp?
12 Replies
ZachDaniel
ZachDaniel3w ago
Hm...it doesn't really make sense to have a calculation with a parent reference in it right then because parent is set by the context the calculation is used in Can you try inlining it instead of using a calculation? Does that work?
⿻ eileen
⿻ eileenOP3w ago
On the scan unapproved_node_issues relationship? If I put this on scan, it does not work:
has_many :node_issues, NodeIssue do
public? true

filter expr(
not exists(
scan.page.site.approved_issues,
rule_id == parent(rule_id) and
target == parent(target)
)
)
end
has_many :node_issues, NodeIssue do
public? true

filter expr(
not exists(
scan.page.site.approved_issues,
rule_id == parent(rule_id) and
target == parent(target)
)
)
end
But also, I wouldn't expect it to because parent now refers to the scan... so I'm not sure how to compare basically a list of the site's approved node_issues against the scan's node_issues via an expr I would prefer this 2nd version to the first if I could just figure out the syntax Assuming it's possible
ZachDaniel
ZachDaniel3w ago
Oh, sorry I misunderstood Um...so that calculation works on its own but not in that relationship?
⿻ eileen
⿻ eileenOP3w ago
it does, yeah
ZachDaniel
ZachDaniel3w ago
Strange. Are you fully up to date? Ash_postgres and ash_sql etc
⿻ eileen
⿻ eileenOP3w ago
3.5.39 Hrm
ZachDaniel
ZachDaniel3w ago
I don't know what the latest versions are off the top of my head 🙂 But if that's the latest then good 😂
⿻ eileen
⿻ eileenOP3w ago
Yeah I was pretty up to date and still get that error on the latest versions I can try to make a repro later if that would help?
ZachDaniel
ZachDaniel3w ago
It would indeed 🙂
⿻ eileen
⿻ eileenOP3w ago
Oh snap! I'm using AshCloak on that field so instead of target I have to use encrypted_target Tests still aren't passing but I'm not getting that error anymore. Creating a repro can be so clarifying So this is interesting. In order to match against my encrypted field, I basically need to create another derived field from it. In this case I'm calling it hashed_target and I'm just running the original target through sha256 encryption. Claude tells me I could also use a cloak cipher that is deterministic to allow for matching, but I'd rather not since that's weaker security and target may actually contain PPI. I'm half wondering if something like this could be added as an option to ash_cloak? As in would you theoretically be open to a PR on that front? Goes a little somethin' like this. I only need to run this on :create and for the one attribute but this is the gist.
defmodule MyApp.SetTargetHashBeforeAction do
use Ash.Resource.Change

@impl true
def change(chg, _opts, _ctx) do
chg |> Ash.Changeset.before_action(&do_change/1, prepend?: true)
end

defp do_change(chg) do
case Ash.Changeset.fetch_argument(chg, :target) do
{:ok, target} ->
chg
|> Ash.Changeset.force_change_attribute(
:hashed_target,
:crypto.hash(:sha256, target) |> Base.encode16(case: :lower)
)

_ ->
chg
end
end

@impl true
def atomic(chg, _opts, _ctx), do: {:ok, do_change(chg)}
end
defmodule MyApp.SetTargetHashBeforeAction do
use Ash.Resource.Change

@impl true
def change(chg, _opts, _ctx) do
chg |> Ash.Changeset.before_action(&do_change/1, prepend?: true)
end

defp do_change(chg) do
case Ash.Changeset.fetch_argument(chg, :target) do
{:ok, target} ->
chg
|> Ash.Changeset.force_change_attribute(
:hashed_target,
:crypto.hash(:sha256, target) |> Base.encode16(case: :lower)
)

_ ->
chg
end
end

@impl true
def atomic(chg, _opts, _ctx), do: {:ok, do_change(chg)}
end
ZachDaniel
ZachDaniel3w ago
Possibly open to it? Not sure would have to see what it looks like generic
⿻ eileen
⿻ eileenOP3w ago
The timestamp on that reply 😭 Anywho I'll see how it goes!

Did you find this page helpful?