Packages

Event-driven notification system for Ash Framework with multiple transport types

Current section

Files

Jump to
ash_dispatch lib extensions add_user_relationship transformer.ex
Raw

lib/extensions/add_user_relationship/transformer.ex

defmodule AshDispatch.Extensions.AddUserRelationship.Transformer do
@moduledoc """
Transformer that conditionally adds a `user` belongs_to relationship to the resource.
This replaces the `:user` calculation with a proper relationship so AshTypescript
can load nested fields.
The transformer only creates the relationship if the configured user_resource module
exists at compile time. This avoids warnings when ash_dispatch compiles standalone.
"""
use Spark.Dsl.Transformer
alias AshDispatch.Config
alias Spark.Dsl.Transformer
def transform(dsl) do
# Get user_resource from config
user_resource = Config.user_resource()
if user_resource do
# Try to compile the user_resource module
# This will trigger compilation if we're in the consuming app
# and will raise if the module truly doesn't exist
case Code.ensure_compiled(user_resource) do
{:module, _} ->
# Module exists or was just compiled
add_user_relationship(dsl, user_resource)
{:error, _} ->
# Module doesn't exist (we're in standalone ash_dispatch compilation)
# Leave calculation as-is
{:ok, dsl}
end
else
# No user_resource configured
{:ok, dsl}
end
end
defp add_user_relationship(dsl, user_resource) do
# Remove the :user calculation if it exists
calculations = Transformer.get_entities(dsl, [:calculations])
dsl =
if Enum.any?(calculations, &(&1.name == :user)) do
Transformer.remove_entity(dsl, [:calculations], fn calc -> calc.name == :user end)
else
dsl
end
# Add the :user relationship
relationship = %Ash.Resource.Relationships.BelongsTo{
name: :user,
destination: user_resource,
source_attribute: :user_id,
destination_attribute: :id,
allow_nil?: true,
public?: true,
define_attribute?: false
}
{:ok, Transformer.add_entity(dsl, [:relationships], relationship)}
end
end