Loading related resource, filtered using a property on the Join Table
https://hexdocs.pm/ash/relationships.html#more-complex-data-loading
Looking here I see I can specify a query for the loaded resource which is sweet. What I'm wondering is if we have some metadata about the relationship present on the join table, what is the right/ash way to filter the loaded tables? A contrived example would be check User A's relationship to other users, filtered on created_date or some enum. Specifically for many_to_many, though I assume the answer would apply for all
29 Replies
At the moment, in order to do that what you'd need to do is load the relationship through the join table I believe.
For example:
Would that Query.load be a standalone query, so query the join_table with the filter of User A and the extra filter we want? Or is the load :join_relationship part of the resource query? I tried the latter and am getting errors
I guess what I'm wondering is if its possible to
Well, kind of
So every
many_to_many
relationship has a corresponding has_many
relationship
if you don't configure it, we call it <name>_join_relationship
So you can do what you had there, but you'd have to go through the join resource
There are some ways to solve for this, specifically manual relationships and/or calculations
which allow you to write arbitrary code to produce the result set you wantYeah this felt like something that would be cleanest with calculations. Haven't done anything with those yet
Manual relationships are also quite useful because they can be upgraded to be filterable using
AshPostgres.ManualRelationship
, where you provide the underlying ecto join implementation
So if the product of a calculation is one or more other resources, a manual relationship should be preferred
although at the moment, you can't provide arguments to a manual relationship
It won't hurt to start it as a calculation to start thoughThank you!
If I want to be able to hook up a form to let the user change the join_params, I see there is this
_join
but I don't quite understand it. This field should be present using auto?:true on in for_create
, for_update
of a many_to_many resource? I am not seeing it, I assume it has something to do with managed relationships? https://hexdocs.pm/ash_phoenix/AshPhoenix.Form.Auto.html#module-many-to-many-relationshipsYeah, so what you'd need to do is configure the join writable fields in the
manage_relationship
call
The docs for Ash.Changeset.manage_relationship
show how that can be done, but it requires setting explicit options
That is the example for on_lookup
So if you want to support something like [:foo]
being editable on the join resource action, you'd do something like this:
I'd really like to change that format at some point to support a nested keyword list so you don't have to provide action names just to change the join fields, i.e on_match: [join_attributes: [:foo]]
, but thats for another day.
But that would pass the :foo
field along to the join resource actions, and should cause the :_join
form to be addedIs there has_many through?
There is not (but if the link is only one relationship away, that is the same as a
many_to_many
)Also thanks a ton for all the responses. Got the join relationship forms working
Eventually I'd like to have
has_many ..., through: [:arbitrary, :link, :of, :things]
and has_one ...., through: [...]
Yeah I see some past chatter about through chaining
What would the API of that be for keyword list? I see with many_to_many you specify source/destination attributes for the through. How could you condense into keyword list for each step of the through chain
Picking up elixir so learning how people think about these keyword config lists is super helpful
In that case, it would be referring to already defined relationships on the other resources
So it would just be a list of atoms
ahhhhh that makes sense
Which, honestly, would not be difficult to define as a manual relationship
so the agreement would be if you want to do 2+ level through chains, create resources for your join tables
Yeah, well currently we need a resource for everything
and although its more verbose than something like ecto which allows you to state just the join table as a string, in Ash it makes sense because everything we do is based off of configuration of resource actions
So you could even do things like write policies on the join resource and have those enforced
I like having everything explicit
Ash feels like it does lots of magic, so having the configuration at least not be magic is a good compromise
Decided I'm gonna explicitly create the join has_many resources too and set w
join_relationship
Yeah, I can see why you'd do that 👍
first class the link relationship
woah! so the main verboseness of a manualrelationship is defining the
load
? Because otherwise that doesn't seem so badIt depends 🙂
If all you want to do is load the related data (and not filter/aggregate the values), then yes
but if you want to do things like
Ash.Query.filter(query, exists(foos, bar == ^baz))
ahhh
Then you'll need to do
use AshPostgres.ManualRelationship
, and define how to join to the targetThanks 🙂
my pleasure 🙂
If you think you'll have lots of "through" relationships, you could try and throw a generic manual relationship together, and we could potentially put it up in a guide while waiting for it to be implemented in core.
Believe only 1 level so far, but there's a chance I run into 2 soon. In which case, definitely