get selected fields in create/update action
barnabasj:
Hi, I have this policy to check if a user is only selecting fields that they are allowed to see. This worked well for reads because it was possible to get the selected/loaded fields from the query. Is it possible to do something similar for
mutations
defmodule Demo.Policies.SelectsAllowedFields do
@moduledoc """
Checks if an action selects only fields that are allowed
Takes a mapping of roles to allowed fields as well as a bypass option
to circumvent the check for a given role
e.g:
user: [:id, :name, :last_name],
super_user: [:id, :address],
bypass: admin
"""
use Ash.Policy.SimpleCheck
require Logger
@impl true
def describe(_) do
"Checks if only allowed fields are selected"
end
@impl true
def match?(actor, context, options) do
bypass_role = options[:bypass]
matched =
case get_role(actor) do
role when is_atom(bypass_role) and role == bypass_role ->
true
role ->
match(
options[role],
[]
|> Enum.concat(get_selects(context))
|> Enum.concat(get_loads(context))
|> Enum.concat(get_calculations(context))
|> Enum.concat(get_aggregates(context))
)
end
if not matched do
dbg()
allowed_fields = options[get_role(actor)] || []
selected_fields =
[]
|> Enum.concat(get_selects(context))
|> Enum.concat(get_loads(context))
|> Enum.concat(get_calculations(context))
|> Enum.concat(get_aggregates(context))
Logger.debug("""
Actor (#{Map.get(actor, :id, "unknown")}) with role #{get_role(actor)} tried to access resource #{context.resource}"
selecting: #{inspect(selected_fields)}
allowed: #{inspect(allowed_fields)}
diff: #{inspect(selected_fields -- allowed_fields)}
""")
end
matched
end
def get_role(%{roles: roles}) when is_list(roles), do: List.first(roles)
def get_role(_), do: nil
# Get all attributes from the resource struct if no fields are selected
#
# @see https://www.ash-hq.org/docs/module/ash/2.4.10/ash-query#function-select-3
#
# ignore meta fields starting with `__`
# and field with structs as values as those point to
# calculations/aggregates/relationships
defp get_selects(%{query: %{select: nil}, resource: resource}),
do: get_resource_fields(resource)
defp get_selects(%{query: nil, resource: resource}),
do: get_resource_fields(resource)
defp get_selects(%{query: %{select: select}}), do: select
defp get_selects(e), do: raise(e)
defp get_resource_fields(resource) do
struct = resource.__struct__
struct
|> Map.keys()
|> Enum.filter(fn key ->
!String.starts_with?(to_string(key), "__") and
!Enum.any?([:aggregates, :calculations], fn special_field -> special_field == key end) and
!is_struct(
Map.get(
struct,
key
)
)
end)
end
defp get_loads(%{query: %{load: load}}), do: Keyword.keys(load)
defp get_loads(_), do: []
defp get_calculations(%{query: %{calculations: calculations}}), do: Map.keys(calculations)
defp get_calculations(_), do: []
defp get_aggregates(%{query: %{aggregates: aggregates}}), do: Map.keys(aggregates)
defp get_aggregates(_), do: []
defp match(allowed_fields, selected_fields)
when is_list(allowed_fields) and is_list(selected_fields) do
case selected_fields -- allowed_fields do
[] ->
true
_ ->
false
end
end
defp match(_, _), do: false
end
zachdaniel:
š¤ currently, not really. You can get the selected fields
zachdaniel:
because there is a
select
option on changeset
zachdaniel:
but we would need to add
load
to changeset as well
zachdaniel:
which would make sense to do š
zachdaniel:
Let me take a look
barnabasj:
I thought I read somewhere in the docs that itās not possible to load stuff with
mutations
. But its been a while so not sure
zachdaniel:
Yeah, there is a way to load them but its done with
api.load
after the initial create
zachdaniel:
Iāll give you the first sneak preview of what Iām working on this week to solve for this need
zachdaniel:
field_policy :field do
authorize_if expr(id == ^actor(:id))
authorize_if SomeRuntimeCheck # forbidden if you're filtering on this
end
zachdaniel:
It will come w/ a similar thing to
%Ash.NotLoaded{}
called
%Ash.ForbiddenField{}
zachdaniel:
and it will resolve that field to a forbidden error in gql (the entire request wonāt be forbidden, but the fields you canāt see will have a forbidden error in their resolution
zachdaniel:
The other aspect of this though is that we will actually deprecate
loading?
checks in policies
zachdaniel:
You can still use
selecting
, but everything related to can you load X should be done as a field policy
barnabasj:
Fortunately I never used loading?, I did it all with this extension so far. But until now it was almost exlcusivly reads.
zachdaniel:
Yeah, there is an issue w/ that though
zachdaniel:
specifically we donāt rerun a read action on
api.load
zachdaniel:
all of our authorization is done as ārow levelā
zachdaniel:
so if you can see a row, it lets you
api.load
anything on it.
zachdaniel:
AshGraphql
first gets the record and uses
api.load
zachdaniel:
meaning your policies might not be doing what you think they are doing š¢
barnabasj:
But the query for the first resource would still be getting the
load
list in the query right? If so I would already check for this on the first resource, if not I do have policies on all the related resources as well so I should be good for now. But definitly something to consider
zachdaniel:
the current implementation it will not get the load, no
zachdaniel:
the load happens later
barnabasj:
this will trigger the policy on the loaded resource though right?
zachdaniel:
yeah, all resource policies are still run
zachdaniel:
but aggregates/calculations will always appear to not be being loaded
barnabasj:
Great, in that case I will be able to sleep tonight š¤£
zachdaniel:
So like if you have a calculation youāre locking down using that check you showed me to see if its being loaded
zachdaniel:
it will always appear that its not being loaded
zachdaniel:
selected attributes will always be correct though
barnabasj:
ok, that probably means all my calculations are not secured, because there are no policies attached to calculation directly, same with aggregates. But relationships should be ok
zachdaniel:
zachdaniel:
Well, if youāre locking down calcs/aggs that way, Iām sorry
zachdaniel:
Its definitely not clear that this is how it works in the docs, hopefully will have field policies done this week
barnabasj:
Just to make sure, policies for calculation would only work correctly with the
loading?
policy right now?
zachdaniel:
policies for aggregates and calculations wonāt work with ash_graphql essentially no matter how it works
zachdaniel:
Actually, just calculations, yeah
zachdaniel:
because it does use
Ash.Query.load
for aggregates
zachdaniel:
actuallyā¦I can make this better sooner
zachdaniel:
one sec
zachdaniel:
I added something to core recently that should let me make
AshGraphql
use
Ash.Query.load
for calculations
zachdaniel:
So then the only problem would be if you tried to use
loading?
with a relationship
zachdaniel:
i.e in your case you have
get_loads
that will always appear empty
frankdugan3:
Sounds like these kinds of policy expectations would a good thing to add to my appās integration tests for the GraphQL API. š
zachdaniel:
ah, okay but there is an implementation detail you need to know about for your
get_calculations
using this new stuff:
defp get_calculations(%{query: %{calculations: calculations}}), do: calculations |> Map.values() |> Enum.map(&(&1.calc_name)) |> Enum.reject(&is_nil/1)
defp get_calculations(_), do: []
zachdaniel:
So there may actually be a way to solve this without the need for
field_policies
(although field policies would be nice to have). The primary reason that
ash_graphql
canāt use
Ash.Query.load
is because the caller might do this:
things{
relationship(limit: 10) {
}
relationship(limit: 2) {
}
}
zachdaniel:
Right now, there is not a way to load the same relationship two different ways
zachdaniel:
so
AshGraphql
uses
api.load
after the fact to account for that. But if I add
Ash.Query.load_relationship_as
in the same way we have
Ash.Query.load_calculation_as
, and add a
relationships
key to the resource similar to
calculations
and
aggregates
for āanonymousā calcs/aggs, then we can create a single
Ash.Query.load
statement, and then your policies will work 100% as you have them
zachdaniel:
(as long as you add that
get_calculations/1
change I mentioned above)
zachdaniel:
I could potentially do that to start, and then add field policies after. That would prevent any unexpected behavior for current implementations. But once
field_policy
is added, Iād still want people to use that because it will play nice with
api.load
if someone uses it elsewhere
zachdaniel:
Okay <@360450161845075968> if you try
main
of
ash_graphql
with the latest release of
ash
(2.9.19), and make that
get_calculations/1
change, that check should now honor loaded calcs in
ash_graphql
barnabasj:
thanks i will have a look at it shortly
zachdaniel:
As for the original question: Iām going to be adding
Ash.Changeset.load
and your policy will then be usable on changesets as well in almost exactly the same way.
zachdaniel:
You should do it with aggregates too, actually:
defp get_aggregates(%{query: %{aggregates: aggregates}}), do: aggregates |> Map.values() |> Enum.map(&(&1.agg_name)) |> Enum.reject(&is_nil/1)
defp get_aggregates(_), do: []
barnabasj:
<@816769011533742100> might be interesting for you
barnabasj:
A quick test looked promising. The policy seems to work, but Iām getting an error down the line. Not 100% sure if that is just coincidental or related. Will take a closer look tomorrow
[error] Task #PID<0.1700.0> started from #PID<0.1695.0> terminating
** (KeyError) key :source_attribute not found in: nil. If you are using the dot syntax, such as map.field, make sure the left-hand side of the dot is a map
(ash 2.9.19) lib/ash/actions/read.ex:1472: anonymous fn/3 in Ash.Actions.Read.calculation_dependency_requests/9
(elixir 1.14.3) lib/enum.ex:4249: Enum.flat_map_list/2
(ash 2.9.19) lib/ash/actions/read.ex:1461: anonymous fn/9 in Ash.Actions.Read.calculation_dependency_requests/9
(elixir 1.14.3) lib/enum.ex:4249: Enum.flat_map_list/2
(elixir 1.14.3) lib/enum.ex:4250: Enum.flat_map_list/2
(ash 2.9.19) lib/ash/actions/read.ex:820: anonymous fn/4 in Ash.Actions.Read.data_field/3
(ash 2.9.19) lib/ash/engine/engine.ex:537: anonymous fn/2 in Ash.Engine.run_iteration/1
(ash 2.9.19) lib/ash/engine/engine.ex:558: anonymous fn/4 in Ash.Engine.async/2
(elixir 1.14.3) lib/task/supervised.ex:89: Task.Supervised.invoke_mfa/2
(elixir 1.14.3) lib/task/supervised.ex:34: Task.Supervised.reply/4
(stdlib 4.2) proc_lib.erl:240: :proc_lib.init_p_do_apply/3
(ash 2.9.19) lib/ash/engine/engine.ex:552: Ash.Engine.async/2
(elixir 1.14.3) lib/enum.ex:1658: Enum."-map/2-lists^map/1-0-"/2
(ash 2.9.19) lib/ash/engine/engine.ex:702: Ash.Engine.start_pending_tasks/1
(ash 2.9.19) lib/ash/engine/engine.ex:323: Ash.Engine.run_to_completion/1
(ash 2.9.19) lib/ash/engine/engine.ex:252: Ash.Engine.do_run/2
(ash 2.9.19) lib/ash/engine/engine.ex:148: Ash.Engine.run/2
(ash 2.9.19) lib/ash/actions/read.ex:173: Ash.Actions.Read.do_run/3
(ash 2.9.19) lib/ash/actions/read.ex:96: Ash.Actions.Read.run/3
(ash 2.9.19) lib/ash/actions/load.ex:1544: Ash.Actions.Load.artificial_limit_and_offset/9
Function: &:erlang.apply/2
Args: [#Function<15.63837685/1 in Dataloader.Source.AshGraphql.Dataloader.run_batches/1>, ...
zachdaniel:
š¢ Hmmā¦yeah something is up there
zachdaniel:
Iāll have it raise a more informative (but still raise) error in that case that could potentially help track the issue down.
zachdaniel:
okay, Iāve added
Ash.Changeset.load
to ash core, and used it in
AshGraphql
zachdaniel:
The only remaining āissueā is that
AshGraphql
loads related resources after-the-fact, not in the main query
zachdaniel:
Alright, so the last thing to cover this stuff/wrap it up is the ability to load the same relationship multiple times in different ways. Iām not entirely sure how difficult this is going to end up being š But once I do that, I can add utilities like
Ash.Changeset.loading(changeset) => [%Attribute{}, %Calculation{}, %Aggregate{}]
and
Ash.Query.loading
that will get you the list of things being loaded, to abstract away some of that complexity.
barnabasj:
So far everything seems to work, thank you.
barnabasj:
After some further tests, two problems emerged. I found a place where we use the aliases already. There we get this error now:
[error] Task #PID<0.1457.0> started from #PID<0.1450.0> terminating
** (Protocol.UndefinedError) protocol String.Chars not implemented for {:__ash_graphql_calculation__, "image16x9"} of type Tuple
(elixir 1.14.3) lib/string/chars.ex:3: String.Chars.impl_for!/1
(elixir 1.14.3) lib/string/chars.ex:22: String.Chars.to_string/1
(ash 2.9.21) lib/ash/filter/filter.ex:2357: anonymous fn/1 in Ash.Filter.add_expression_part/3
(elixir 1.14.3) lib/enum.ex:1251: anonymous fn/3 in Enum.flat_map/2
(stdlib 4.2) maps.erl:411: :maps.fold_1/3
(elixir 1.14.3) lib/enum.ex:2480: Enum.flat_map/2
(ash 2.9.21) lib/ash/filter/filter.ex:2356: Ash.Filter.add_expression_part/3
(ash 2.9.21) lib/ash/filter/filter.ex:2078: anonymous fn/3 in Ash.Filter.parse_expression/2
(elixir 1.14.3) lib/enum.ex:4751: Enumerable.List.reduce/3
(elixir 1.14.3) lib/enum.ex:2514: Enum.reduce_while/3
(ash 2.9.21) lib/ash/filter/filter.ex:314: Ash.Filter.parse/5
(ash 2.9.21) lib/ash/query/query.ex:2032: Ash.Query.do_filter/2
(ash 2.9.21) lib/ash/actions/load.ex:1750: Ash.Actions.Load.get_query/4
(ash 2.9.21) lib/ash/actions/load.ex:969: anonymous fn/10 in Ash.Actions.Load.data/10
(ash 2.9.21) lib/ash/engine/engine.ex:537: anonymous fn/2 in Ash.Engine.run_iteration/1
(ash 2.9.21) lib/ash/engine/engine.ex:558: anonymous fn/4 in Ash.Engine.async/2
(elixir 1.14.3) lib/task/supervised.ex:89: Task.Supervised.invoke_mfa/2
(elixir 1.14.3) lib/task/supervised.ex:34: Task.Supervised.reply/4
(stdlib 4.2) proc_lib.erl:240: :proc_lib.init_p_do_apply/3
(ash 2.9.21) lib/ash/engine/engine.ex:552: Ash.Engine.async/2
Function: &:erlang.apply/2
Args: [#Function<15.63837685/1 in Dataloader.Source.AshGraphql.Dataloader.run_batches/1>,
barnabasj:
And I had a calculation that worked before now triggers this error:
[error] Task #PID<0.1708.0> started from #PID<0.1698.0> terminating
** (RuntimeError) Internal Error:
Calculation depends on relationship but we could not determine the relationship
Resource: JdlEngine.Inventory.Resources.Hotel
Relationship Dependency:
%{path: [hotel_itinerary_items: #Ash.Query<resource: Demo.Offer.Resources.ItineraryItem.HotelItineraryItem>, hotel: #Ash.Query<resource: Demo.Inventory.Resources.Hotel>], query: #Ash.Query<resource: Demo.Geo.Resources.Country>, relationship: :country, type: :relationship}
(ash 2.9.21) lib/ash/actions/read.ex:1500: anonymous fn/15 in Ash.Actions.Read.calculation_dependency_requests/9
(elixir 1.14.3) lib/enum.ex:4249: Enum.flat_map_list/2
(elixir 1.14.3) lib/enum.ex:4250: Enum.flat_map_list/2
(ash 2.9.21) lib/ash/actions/read.ex:1479: anonymous fn/10 in Ash.Actions.Read.calculation_dependency_requests/9
(elixir 1.14.3) lib/enum.ex:4249: Enum.flat_map_list/2
(elixir 1.14.3) lib/enum.ex:4250: Enum.flat_map_list/2
(ash 2.9.21) lib/ash/actions/read.ex:838: anonymous fn/4 in Ash.Actions.Read.data_field/3
(ash 2.9.21) lib/ash/engine/engine.ex:537: anonymous fn/2 in Ash.Engine.run_iteration/1
(ash 2.9.21) lib/ash/engine/engine.ex:558: anonymous fn/4 in Ash.Engine.async/2
(elixir 1.14.3) lib/task/supervised.ex:89: Task.Supervised.invoke_mfa/2
(elixir 1.14.3) lib/task/supervised.ex:34: Task.Supervised.reply/4
(stdlib 4.2) proc_lib.erl:240: :proc_lib.init_p_do_apply/3
(ash 2.9.21) lib/ash/engine/engine.ex:552: Ash.Engine.async/2
(elixir 1.14.3) lib/enum.ex:1658: Enum."-map/2-lists^map/1-0-"/2
(ash 2.9.21) lib/ash/engine/engine.ex:702: Ash.Engine.start_pending_tasks/1
(ash 2.9.21) lib/ash/engine/engine.ex:323: Ash.Engine.run_to_completion/1
(ash 2.9.21) lib/ash/engine/engine.ex:252: Ash.Engine.do_run/2
(ash 2.9.21) lib/ash/engine/engine.ex:148: Ash.Engine.run/2
(ash 2.9.21) lib/ash/actions/read.ex:173: Ash.Actions.Read.do_run/3
(ash 2.9.21) lib/ash/actions/read.ex:96: Ash.Actions.Read.run/3
Function: &:erlang.apply/2
Args: [#Function<15.63837685/1 in Dataloader.Source.AshGraphql.Dataloader.run_batches/1>,
I tried to debug the second error a bit, and it seems it is looking for a hotel relationship on the hotel instead of the items, but Iām not sure why
zachdaniel:
Will look into these both today.
barnabasj:
ash: 8fdd319697ff39262fc4162f38fd6c55e2b9b189 is the last commit that I know worked for us in relation to the query/loads. Policy problems aside
barnabasj:
This is the load statement in the calc that now fails:
@impl true
def load(_, _, _) do
[
hotel_itinerary_items:
Demo.Offer.Resources.ItineraryItem.HotelItineraryItem
|> Ash.Query.load(
hotel:
Demo.Inventory.Resources.Hotel
|> Ash.Query.select(:id)
|> Ash.Query.load(:country)
)
|> Ash.Query.load(:sort_order),
villa_itinerary_items:
Demo.Offer.Resources.ItineraryItem.VillaItineraryItem
|> Ash.Query.load(
villa:
Demo.Inventory.Resources.Villa
|> Ash.Query.select(:id)
|> Ash.Query.load(:country)
)
|> Ash.Query.load(:sort_order)
]
end
zachdaniel:
Okay, so I just pushed up a fix for the first issue
zachdaniel:
the second one might be more complicated
zachdaniel:
If youāre still around, the error message I was outputting there is actually wrong a bit
barnabasj:
i can try it shortly
zachdaniel:
awesome, thanks
zachdaniel:
actually we need both
zachdaniel:
okay, just pushed a better message up to main, hopefully will help me track the error down
barnabasj:
Getting the same error here: https://discordapp.com/channels/711271361523351632/1115269100860616735/1115929808187179033
barnabasj:
The calc load now givs me this error:
[error] Task #PID<0.6739.0> started from #PID<0.6731.0> terminating
** (RuntimeError) Internal Error:
Calculation depends on relationship but we could not determine the relationship
Resource: Demo.Inventory.Resources.Hotel
Dependency:
%{path: [hotel_itinerary_items: #Ash.Query<resource: Demo.Offer.Resources.ItineraryItem.HotelItineraryItem>], query: #Ash.Query<resource: Demo.Inventory.Resources.Hotel, select: [:id]>, relationship: :hotel, type: :relationship}
Relationship Dependency:
%{path: [hotel_itinerary_items: #Ash.Query<resource: Demo.Offer.Resources.ItineraryItem.HotelItineraryItem>, hotel: #Ash.Query<resource: Demo.Inventory.Resources.Hotel, select: [:id]>], query: #Ash.Query<resource: Demo.Geo.Resources.Country>, relationship: :country, type: :relationship}
(ash 2.9.21) lib/ash/actions/read.ex:1493: anonymous fn/3 in Ash.Actions.Read.calculation_dependency_requests/9
(elixir 1.14.3) lib/enum.ex:4249: Enum.flat_map_list/2
(ash 2.9.21) lib/ash/actions/read.ex:1479: anonymous fn/9 in Ash.Actions.Read.calculation_dependency_requests/9
(elixir 1.14.3) lib/enum.ex:4249: Enum.flat_map_list/2
(elixir 1.14.3) lib/enum.ex:4250: Enum.flat_map_list/2
(ash 2.9.21) lib/ash/actions/read.ex:838: anonymous fn/4 in Ash.Actions.Read.data_field/3
(ash 2.9.21) lib/ash/engine/engine.ex:537: anonymous fn/2 in Ash.Engine.run_iteration/1
(ash 2.9.21) lib/ash/engine/engine.ex:558: anonymous fn/4 in Ash.Engine.async/2
(elixir 1.14.3) lib/task/supervised.ex:89: Task.Supervised.invoke_mfa/2
(elixir 1.14.3) lib/task/supervised.ex:34: Task.Supervised.reply/4
(stdlib 4.2) proc_lib.erl:240: :proc_lib.init_p_do_apply/3
(ash 2.9.21) lib/ash/engine/engine.ex:552: Ash.Engine.async/2
(elixir 1.14.3) lib/enum.ex:1658: Enum."-map/2-lists^map/1-0-"/2
(ash 2.9.21) lib/ash/engine/engine.ex:702: Ash.Engine.start_pending_tasks/1
(ash 2.9.21) lib/ash/engine/engine.ex:323: Ash.Engine.run_to_completion/1
(ash 2.9.21) lib/ash/engine/engine.ex:252: Ash.Engine.do_run/2
(ash 2.9.21) lib/ash/engine/engine.ex:148: Ash.Engine.run/2
(ash 2.9.21) lib/ash/actions/read.ex:173: Ash.Actions.Read.do_run/3
(ash 2.9.21) lib/ash/actions/read.ex:96: Ash.Actions.Read.run/3
(ash 2.9.21) lib/ash/actions/load.ex:1549: Ash.Actions.Load.artificial_limit_and_offset/9
Function: &:erlang.apply/2
barnabasj:
what I do not understand about this error message is why is the Hotel the resource, because the calculation is on the collection which is not in the error message so the load would be collection -> hotel_itinerary_items -> hotel -> country
zachdaniel:
are you sure its the same error? could there be a different stacktrace?
barnabasj:
let me check,
barnabasj:
[error] Task #PID<0.7072.0> started from #PID<0.7061.0> terminating
** (Ash.Error.Unknown) Unknown Error
Context: resolving data on process Demo.Offer.Resources.ItineraryCollection.Image.read
* Context: resolving data on process Demo.Offer.Resources.ItineraryCollection.Image.read
** (Protocol.UndefinedError) protocol String.Chars not implemented for {:__ash_graphql_calculation__, "image16x9"} of type Tuple
(elixir 1.14.3) lib/string/chars.ex:3: String.Chars.impl_for!/1
(elixir 1.14.3) lib/string/chars.ex:22: String.Chars.to_string/1
(ash 2.9.21) lib/ash/actions/read.ex:2525: Ash.Actions.Read.calculation_request/14
(elixir 1.14.3) lib/enum.ex:1658: Enum."-map/2-lists^map/1-0-"/2
(ash 2.9.21) lib/ash/actions/read.ex:2661: Ash.Actions.Read.add_calculation_values/14
(ash 2.9.21) lib/ash/actions/read.ex:411: anonymous fn/8 in Ash.Actions.Read.as_requests/5
(ash 2.9.21) lib/ash/engine/request.ex:1048: Ash.Engine.Request.do_try_resolve_local/4
(ash 2.9.21) lib/ash/engine/request.ex:282: Ash.Engine.Request.do_next/1
(ash 2.9.21) lib/ash/engine/request.ex:211: Ash.Engine.Request.next/1
(ash 2.9.21) lib/ash/engine/engine.ex:712: Ash.Engine.advance_request/2
(ash 2.9.21) lib/ash/engine/engine.ex:637: Ash.Engine.fully_advance_request/2
(ash 2.9.21) lib/ash/engine/engine.ex:578: Ash.Engine.do_run_iteration/2
(elixir 1.14.3) lib/enum.ex:2468: Enum."-reduce/3-lists^foldl/2-0-"/3
(ash 2.9.21) lib/ash/engine/engine.ex:307: Ash.Engine.run_to_completion/1
(ash 2.9.21) lib/ash/engine/engine.ex:252: Ash.Engine.do_run/2
(ash 2.9.21) lib/ash/engine/engine.ex:148: Ash.Engine.run/2
(ash 2.9.21) lib/ash/actions/read.ex:173: Ash.Actions.Read.do_run/3
(ash 2.9.21) lib/ash/actions/read.ex:96: Ash.Actions.Read.run/3
(ash 2.9.21) lib/ash/actions/load.ex:1549: Ash.Actions.Load.artificial_limit_and_offset/9
(ash 2.9.21) lib/ash/actions/load.ex:977: anonymous fn/10 in Ash.Actions.Load.data/10
(elixir 1.14.3) lib/string/chars.ex:3: String.Chars.impl_for!/1
(elixir 1.14.3) lib/string/chars.ex:22: String.Chars.to_string/1
(ash 2.9.21) lib/ash/actions/read.ex:2525: Ash.Actions.Read.calculation_request/14
(elixir 1.14.3) lib/enum.ex:1658: Enum."-map/2-lists^map/1-0-"/2
(ash 2.9.21) lib/ash/actions/read.ex:2661: Ash.Actions.Read.add_calculation_values/14
(ash 2.9.21) lib/ash/actions/read.ex:411: anonymous fn/8 in Ash.Actions.Read.as_requests/5
(ash 2.9.21) lib/ash/engine/request.ex:1048: Ash.Engine.Request.do_try_resolve_local/4
(ash 2.9.21) lib/ash/engine/request.ex:282: Ash.Engine.Request.do_next/1
(ash 2.9.21) lib/ash/engine/request.ex:211: Ash.Engine.Request.next/1
(ash 2.9.21) lib/ash/engine/engine.ex:712: Ash.Engine.advance_request/2
(ash 2.9.21) lib/ash/engine/engine.ex:637: Ash.Engine.fully_advance_request/2
(ash 2.9.21) lib/ash/engine/engine.ex:578: Ash.Engine.do_run_iteration/2
(elixir 1.14.3) lib/enum.ex:2468: Enum."-reduce/3-lists^foldl/2-0-"/3
(ash 2.9.21) lib/ash/engine/engine.ex:307: Ash.Engine.run_to_completion/1
(ash 2.9.21) lib/ash/engine/engine.ex:252: Ash.Engine.do_run/2
(ash 2.9.21) lib/ash/engine/engine.ex:148: Ash.Engine.run/2
(ash 2.9.21) lib/ash/actions/read.ex:173: Ash.Actions.Read.do_run/3
(ash 2.9.21) lib/ash/actions/read.ex:96: Ash.Actions.Read.run/3
(ash 2.9.21) lib/ash/actions/load.ex:1549: Ash.Actions.Load.artificial_limit_and_offset/9
(ash 2.9.21) lib/ash/actions/load.ex:977: anonymous fn/10 in Ash.Actions.Load.data/10
Function: &:erlang.apply/2
barnabasj:
ok, yeah stack trace is bigger <a:facepalm:803600909254131722>
zachdaniel:
okay, pushed up another fix for that
zachdaniel:
just more places weāre thinking we can do
to_string(calc.name)
but we canāt always
zachdaniel:
could potentially be more, its hard to find them all the time š Iām surprised tests in
ash_graphql
didnāt find this. I guess its because it didnāt test dynamic calcs with calcs with dependencies
zachdaniel:
okay, and I think I found the issue for the dependency issue also
zachdaniel:
so
main
should have fixes for both hopefully
barnabasj:
%{
{:__ash_graphql_calculation__, "image16x9"} => #Demo.Calculations.ImageUrlCaculation<[]> - %{named_transformations: ["crop_16:9_centered"]}
}
calculation: %{
calc_name: {:__ash_graphql_calculation__, "image16x9"},
constraints: [allow_empty?: false, trim?: true],
context: %{
I logged the calculations in the query, I was just wondering why the calc_name was not the original calc name. Is there a way to get the original calc name from the alias?
zachdaniel:
oh
zachdaniel:
yeah that is what that is supposed to be
zachdaniel:
thanks for pointing that out
zachdaniel:
calc_name
should be
nil
for anonymous calculations (which you canāt do through the api) and
:the_resource_calc_name
otherwise
zachdaniel:
okay, pushed a fix for that as well
barnabasj:
great, thanks. now i can get the correct calc name and check if the user is allowed to get it too š
zachdaniel:
š„³ š„³ š„³
barnabasj:
Just clicked through all the pages, looks like everything is working now <a:party_parrot:1085610631912226846>