2023-04-28 14:07:05 +12:00
|
|
|
defmodule AshOban.Transformers.SetDefaults do
|
2023-09-17 03:17:40 +12:00
|
|
|
# Set trigger default values
|
|
|
|
@moduledoc false
|
2023-04-28 14:36:29 +12:00
|
|
|
|
2023-04-28 14:07:05 +12:00
|
|
|
use Spark.Dsl.Transformer
|
|
|
|
alias Spark.Dsl.Transformer
|
|
|
|
|
|
|
|
def after?(AshOban.Transformers.DefineSchedulers), do: false
|
|
|
|
def after?(_), do: true
|
|
|
|
def before?(AshOban.Transformers.DefineSchedulers), do: true
|
|
|
|
def before?(_), do: false
|
|
|
|
|
2023-04-28 14:36:29 +12:00
|
|
|
# sobelow_skip ["DOS.BinToAtom"]
|
2023-04-28 14:07:05 +12:00
|
|
|
def transform(dsl) do
|
|
|
|
module = Transformer.get_persisted(dsl, :module)
|
|
|
|
|
|
|
|
{:ok,
|
|
|
|
dsl
|
2024-03-30 12:52:22 +13:00
|
|
|
|> set_domain(module)
|
2023-12-08 07:24:16 +13:00
|
|
|
|> set_trigger_defaults(module)
|
2023-12-08 08:24:23 +13:00
|
|
|
|> set_scheduled_action_defaults(module)
|
|
|
|
|> validate_global_uniqueness(module)}
|
|
|
|
end
|
|
|
|
|
2024-03-30 12:52:22 +13:00
|
|
|
defp set_domain(dsl, module) do
|
|
|
|
case AshOban.Info.oban_domain(dsl) do
|
|
|
|
{:ok, domain} when not is_nil(domain) ->
|
|
|
|
dsl
|
|
|
|
|
|
|
|
:error ->
|
|
|
|
if domain = Ash.Resource.Info.domain(dsl) do
|
|
|
|
Transformer.set_option(dsl, [:oban], :domain, domain)
|
|
|
|
else
|
|
|
|
raise Spark.Error.DslError,
|
|
|
|
module: module,
|
|
|
|
message:
|
|
|
|
"Resources without a statically configured domain require the `domain` option in the `oban` section."
|
|
|
|
end
|
|
|
|
end
|
|
|
|
end
|
|
|
|
|
2023-12-08 08:24:23 +13:00
|
|
|
defp validate_global_uniqueness(dsl, module) do
|
|
|
|
triggers = AshOban.Info.oban_triggers(dsl)
|
|
|
|
schedulers = AshOban.Info.oban_scheduled_actions(dsl)
|
|
|
|
|
|
|
|
triggers
|
|
|
|
|> Enum.concat(schedulers)
|
|
|
|
|> Enum.map(& &1.name)
|
|
|
|
|> Enum.frequencies()
|
|
|
|
|> Enum.find(fn {_, value} ->
|
|
|
|
value > 1
|
|
|
|
end)
|
|
|
|
|> case do
|
|
|
|
nil ->
|
|
|
|
:ok
|
|
|
|
|
|
|
|
{name, _} ->
|
|
|
|
raise Spark.Error.DslError,
|
|
|
|
path: [:oban, :triggers, name],
|
|
|
|
module: module,
|
|
|
|
message: """
|
|
|
|
The trigger and/or scheduled_action #{inspect(name)} is defined more than once.
|
|
|
|
Names must be unique across scheduled_actions and triggers.
|
|
|
|
"""
|
|
|
|
end
|
|
|
|
|
|
|
|
dsl
|
2023-12-08 07:24:16 +13:00
|
|
|
end
|
|
|
|
|
|
|
|
defp set_scheduled_action_defaults(dsl, module) do
|
|
|
|
dsl
|
|
|
|
|> Transformer.get_entities([:oban, :scheduled_actions])
|
|
|
|
|> Enum.reduce(dsl, fn scheduled_action, dsl ->
|
|
|
|
action_name = scheduled_action.action || scheduled_action.name
|
|
|
|
|
|
|
|
case Ash.Resource.Info.action(dsl, action_name) do
|
|
|
|
nil ->
|
|
|
|
key_name =
|
|
|
|
if scheduled_action.action do
|
|
|
|
:action
|
|
|
|
else
|
|
|
|
:name
|
|
|
|
end
|
|
|
|
|
|
|
|
raise Spark.Error.DslError,
|
|
|
|
path: [:oban, :scheduled_actions, scheduled_action.name, key_name],
|
|
|
|
module: module,
|
|
|
|
message: """
|
|
|
|
No such action #{inspect(action_name)} on #{inspect(module)}.
|
|
|
|
"""
|
|
|
|
|
|
|
|
%{type: bad_type} when bad_type in [:update, :destroy] ->
|
|
|
|
raise Spark.Error.DslError,
|
|
|
|
path: [:oban, :scheduled_actions, scheduled_action.name],
|
|
|
|
module: module,
|
|
|
|
message: """
|
|
|
|
Scheduled actions of type #{inspect(bad_type)} are not supported.
|
|
|
|
"""
|
2023-12-08 07:32:44 +13:00
|
|
|
|
|
|
|
_ ->
|
|
|
|
:ok
|
2023-12-08 07:24:16 +13:00
|
|
|
end
|
|
|
|
|
|
|
|
queue = scheduled_action.queue || default_queue_name(dsl, scheduled_action)
|
|
|
|
|
|
|
|
Transformer.replace_entity(dsl, [:oban, :scheduled_actions], %{
|
|
|
|
scheduled_action
|
|
|
|
| action: action_name,
|
|
|
|
queue: queue
|
|
|
|
})
|
|
|
|
end)
|
|
|
|
end
|
|
|
|
|
|
|
|
defp set_trigger_defaults(dsl, module) do
|
|
|
|
dsl
|
|
|
|
|> Transformer.get_entities([:oban, :triggers])
|
|
|
|
|> Enum.reduce(dsl, fn trigger, dsl ->
|
|
|
|
read_action =
|
|
|
|
case trigger.read_action do
|
|
|
|
nil ->
|
|
|
|
Ash.Resource.Info.primary_action(dsl, :read) ||
|
|
|
|
raise Spark.Error.DslError,
|
|
|
|
path: [
|
|
|
|
:oban,
|
|
|
|
:triggers,
|
|
|
|
trigger.name,
|
|
|
|
:read_action
|
|
|
|
],
|
|
|
|
module: module,
|
|
|
|
message: """
|
|
|
|
No read action was configured for this trigger, and no primary read action exists
|
|
|
|
"""
|
|
|
|
|
|
|
|
read_action ->
|
|
|
|
Ash.Resource.Info.action(dsl, read_action)
|
|
|
|
end
|
|
|
|
|
|
|
|
action_name = trigger.action || trigger.name
|
|
|
|
|
|
|
|
unless Ash.Resource.Info.action(dsl, action_name) do
|
|
|
|
key_name =
|
|
|
|
if trigger.action do
|
|
|
|
:action
|
|
|
|
else
|
|
|
|
:name
|
|
|
|
end
|
|
|
|
|
|
|
|
raise Spark.Error.DslError,
|
|
|
|
path: [:oban, :triggers, trigger.name, key_name],
|
|
|
|
module: module,
|
|
|
|
message: """
|
|
|
|
No such action #{inspect(action_name)} on #{inspect(module)}.
|
|
|
|
"""
|
|
|
|
end
|
|
|
|
|
|
|
|
unless read_action.pagination && read_action.pagination.keyset? do
|
|
|
|
raise Spark.Error.DslError,
|
|
|
|
path: [:oban, :triggers, trigger.name, :read_action],
|
|
|
|
module: module,
|
|
|
|
message: """
|
|
|
|
The read action `:#{read_action.name}` must support keyset pagination in order to be
|
|
|
|
used by an AshOban trigger.
|
|
|
|
"""
|
|
|
|
end
|
|
|
|
|
|
|
|
queue = trigger.queue || default_queue_name(dsl, trigger)
|
|
|
|
|
|
|
|
Transformer.replace_entity(dsl, [:oban, :triggers], %{
|
|
|
|
trigger
|
|
|
|
| read_action: read_action.name,
|
|
|
|
queue: queue,
|
|
|
|
scheduler_queue: trigger.scheduler_queue || queue,
|
|
|
|
action: trigger.action || trigger.name
|
|
|
|
})
|
|
|
|
end)
|
2023-04-28 14:07:05 +12:00
|
|
|
end
|
|
|
|
|
2023-04-28 14:36:29 +12:00
|
|
|
# sobelow_skip ["DOS.BinToAtom"]
|
2023-04-28 14:07:05 +12:00
|
|
|
defp default_queue_name(dsl, trigger) do
|
|
|
|
:"#{Ash.Resource.Info.short_name(dsl)}_#{trigger.name}"
|
|
|
|
end
|
|
|
|
end
|