Skip to content

Instantly share code, notes, and snippets.

@zachdaniel
Created April 16, 2022 15:04
Show Gist options
  • Save zachdaniel/74104b1e1d80c65d8ca4684e0bfd91fe to your computer and use it in GitHub Desktop.
Save zachdaniel/74104b1e1d80c65d8ca4684e0bfd91fe to your computer and use it in GitHub Desktop.
defmodule MyApp.Extensions.Archive.Transformers.SetupArchival do
@moduledoc "Sets up the required resource structure for archival"
use Ash.Dsl.Transformer
@after_transformers [
Ash.Resource.Transformers.SetPrimaryActions
]
@before_transformers [
Ash.Resource.Transformers.DefaultAccept,
Ash.Resource.Transformers.SetTypes
]
alias Ash.Dsl.Transformer
def transform(resource, dsl_state) do
if Ash.Resource.Info.embedded?(resource) || !MyApp.Extensions.Archive.archive?(resource) do
{:ok, dsl_state}
else
dsl_state
|> add_archived_at()
|> update_destroy_actions()
|> add_base_filter()
|> add_base_filter_sql()
end
end
def after?(transformer) when transformer in @after_transformers, do: true
def after?(_), do: false
def before?(transformer) when transformer in @before_transformers, do: true
def before?(_), do: false
defp add_archived_at(dsl_state) do
with {:ok, archived_at} <-
Transformer.build_entity(Ash.Resource.Dsl, [:attributes], :attribute,
name: :archived_at,
type: :utc_datetime_usec,
private?: true,
allow_nil?: true
) do
{:ok, Transformer.add_entity(dsl_state, [:attributes], archived_at)}
end
end
defp update_destroy_actions({:ok, dsl_state}) do
dsl_state
|> Transformer.get_entities([:actions])
|> Enum.filter(&(&1.type == :destroy))
|> Enum.reduce({:ok, dsl_state}, fn destroy_action, {:ok, dsl_state} ->
with {:ok, set_archived_at} <-
Transformer.build_entity(Ash.Resource.Dsl, [:actions, :destroy], :change,
change:
Ash.Resource.Change.Builtins.set_attribute(:archived_at, &DateTime.utc_now/0)
) do
new_action = %{
destroy_action
| soft?: true,
changes: [set_archived_at | destroy_action.changes]
}
{:ok,
Transformer.replace_entity(
dsl_state,
[:actions],
new_action,
&(&1.name == destroy_action.name)
)}
end
end)
end
defp update_destroy_actions({:error, error}), do: {:error, error}
defp add_base_filter({:ok, dsl_state}) do
case Transformer.get_option(dsl_state, [:resource], :base_filter) do
nil ->
{:ok, Transformer.set_option(dsl_state, [:resource], :base_filter, is_nil: :archived_at)}
value ->
{:ok,
Transformer.set_option(dsl_state, [:resource], :base_filter,
and: [[is_nil: :archived_at], value]
)}
end
end
defp add_base_filter({:error, error}) do
{:error, error}
end
defp add_base_filter_sql({:ok, dsl_state}) do
case Transformer.get_option(dsl_state, [:postgres], :base_filter_sql) do
nil ->
{:ok,
Transformer.set_option(dsl_state, [:postgres], :base_filter_sql, "archived_at IS NULL")}
value ->
{:ok,
Transformer.set_option(
dsl_state,
[:postgres],
:base_filter_sql,
"archived_at IS NULL and (#{value})"
)}
end
end
defp add_base_filter_sql({:error, error}) do
{:error, error}
end
end
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment