defmodule MyApp.Location do
use Ash.Resource, data_layer: AshPostgres.DataLayer
postgres do
repo MyApp.Repo
polymorphic? true
end
attributes do
uuid_primary_key :id
attribute :resource_id, :uuid do
allow_nil? false
private? true
end
attribute :x, :float
attribute :y, :float
end
...
That is then used by 2 or 3 other resources, e.g.
defmodule MyApp.Event do
use Ash.Resource, data_layer: AshPostgres.DataLayer
postgres do
repo MyApp.Repo
table "events"
end
attributes do
uuid_primary_key :id
attribute :when, :utc_datetime, allow_nil?: false, default: &DateTime.utc_now/0
attribute :what, :string
attribute :who, :string
end
relationships do
has_one :location, Location do
relationship_context %{data_layer: %{table: "event_locations"}}
destination_attribute :resource_id
end
end
Is it possible to use the references config block somehow to delete Locations when the owning Event is deleted?
If it wasn’t polymorphic, we could do something like this in the Location resource, but given it references a specific relationship it won’t work with a polymorphic resource:
postgres do
repo MyApp.Repo
# polymorphic? true
references do
reference :event, on_delete: :delete
end
end
The obvious (to me) alternative is setting up a destroy action on the Event resource that deletes the associated Location first, but then that has to be repeated for every other resource that may use Location which kinda defeats the purpose of using a polymorphic resource in the first place.
Edit: The destroy action isn’t so easy to get right either - how do you inject the datalayer[:table] context to ensure the delete is applied to the right table?
That sounds straightforward. So I added that to the Location resource (the polymorphic one), and generated the migrations to update the relationship options in Postgres and no migration was generated:
“No changes detected, so no migrations or snapshots have been created.”
I’ll have a bit more of a play with breaking and recreating the relationships.
Edit: Looks like it needed to go on the opposite side of the relationship, i.e. on the Event resource.
That…doesn’t seem right. I can see where it’s doing that, but it doesn’t really make sense to configure that on the other resource. I think that might be a bug.
There are probably some angles to consider. It makes sense to have it on the current side of the relationship if you want to control delete behaviour on a per relationship basis (i.e. Event → Location you may want the “cascade delete”, but Person → Location you may not). However, if you have relationships to two different polymorphic resources, the current approach doesn’t give enough control for per-relationship behaviour anyway.
If it’s on a per polymorphic resource basis it would make sense to swap it around.
Yeah, thats an good point. Regardless of which side you’re configuring it on you’d want to configure it per polymorphic relationship also. Probably needs to just be reworked in general.
It’s in the GH issue - on reflection, this seems to make sense to me given that the implementation details (e.g. table name) are given at this point:
defmodule MyApp.Event do
...
relationships do
has_one :location, Location do
# Data layer context captures implementation details
relationship_context %{data_layer: %{table: "event_locations", on_delete: :delete}}
# or relationship_context %{data_layer: %{table: "event_locations"}, on_delete: :delete}
destination_attribute :resource_id
end
end
...