Custom / virtual fields on read
Hi All,
I am creating an API based on an old system and can't modify the original, but I want to change the way the resources are read. More specifically I want to set a certain virtual field based on the value of an existing database field.
Normally this is something I would achieve with a virtual field and then modify the output in the view layer. But I understand the idiomatic way in Ash is to push as much as possible into the resource.
I read in another post that arguments are basically the equivalent of virtual fields, so looked into setting those based on an attribute value.
What would be the best approach to achieve something like this.
I already experimented with
Ash.Query
a bit, but not sure how to achieve reading an attribute from the fetched resource and setting an argument based on that.
Any advise and/or guidance is much appreciated. I tried to find it in the docs but am a bit lost where to look...
Thanks!9 Replies
Do you want to have a virtual field in your resource whose value is based on the existing field/attribute? If that's the case the you can use
Ash Calculations
: https://ash-hq.org/docs/guides/ash/latest/topics/calculations. For example if you have a User
resource like the following:
you can add a full_name
calculation(virtual field) to your resource by declaring a calculation
:
that way you can now use user.full_name
even if its not defined in your resource attributes
. I think you can use the calculation
in Ash.Query
as well.
If that's not what you're looking for you can share some code to provide additional context.cool! Yes I think that might work. Let me try that.
ok, cool that worked with a custom Calculations module.
For anyone else wondering. I had to set a difficulty level based on a genre, which is in a related resource.
So I created this calculation in the main resource
And then the implementation in that module was just this:
š
thanks for the pointer @Jmanda !
Awesome š„³
Ok, now figuring out how to get it to pass into the graphQL response... š
Ok stuck again. So the code interface works fine, but the graphQL API returns nil for all these calculated fields.
Anyone know how to expose calculated fields in a graphQL API.
It is complaining that my main resource doesn't have a primary read action, but that's not the case, so I guess it has to do with the calculation not having a graphQL type
So I have never used AshGraphql before, but perhaps you can share your code I see how you are defining the GraphQL api in your resource? At least that will provide more context.
You can also try to add
primary? true
to your read
action? And it's likely you're referencing a module that does not exist, take a look at these discussions: https://discord.com/channels/711271361523351632/799097774523547669/861263803056652288 and https://discord.com/channels/711271361523351632/799097774523547669/823438146804252702ok, haha. That simple change, marking one of the read actions as
primary? true
did the trick. Probably the whole graphQL engine just died on me without that...
Thanks for the insights!Something you'll also need to do, is add
def load/3
to express the dependency on genre.identifier
How I'd do that personally:
ok, thanks @Zach Daniel ! Need to wrap my head around this conceptually still, so I'll dig in. I have a similar thing now where I need to conditionally add a filter. So depending on the value of the record I need to do different kinds of filtering. Would that als be something to do in a similar way?
so for instance:
if type == "puzzle" => filter on certain publication dates, if type = "app", don't do those filters.
Basically that could also be a calculation with a constraint. Or can I also add a constraint to a Filter?
Depending on what he design is. You can also do it in a query oreparation
Should be plenty of examples of preparations in the support forum