Packages
ash
2.6.30
3.29.3
3.29.2
3.29.1
3.29.0
3.28.0
3.27.8
3.27.7
3.27.6
3.27.5
3.27.4
3.27.3
3.27.2
3.27.1
3.27.0
3.26.0
3.25.2
3.25.1
3.25.0
retired
3.24.7
3.24.6
3.24.5
3.24.4
3.24.3
3.24.2
3.24.1
3.24.0
3.23.1
3.23.0
3.22.2
3.22.1
3.22.0
3.21.3
3.21.2
3.21.1
3.21.0
3.20.0
3.19.3
3.19.2
3.19.1
3.19.0
3.18.0
3.17.1
3.17.0
3.16.0
3.15.0
3.14.1
3.14.0
retired
3.13.2
3.13.1
3.13.0
3.12.0
3.11.3
3.11.2
3.11.1
3.11.0
3.10.1
3.10.0
3.9.0
3.8.0
3.7.6
3.7.5
3.7.4
3.7.3
3.7.2
3.7.1
3.7.0
retired
3.6.3
retired
3.6.2
3.6.1
3.6.0
3.5.43
3.5.42
3.5.41
3.5.40
3.5.39
3.5.38
3.5.37
3.5.36
3.5.35
3.5.34
3.5.33
3.5.32
3.5.31
3.5.30
3.5.29
3.5.28
3.5.27
3.5.26
3.5.25
3.5.24
3.5.23
3.5.22
3.5.21
3.5.20
3.5.19
3.5.18
3.5.17
3.5.16
3.5.15
3.5.14
3.5.13
3.5.12
3.5.11
3.5.10
3.5.9
3.5.8
3.5.7
3.5.6
3.5.5
3.5.4
3.5.3
3.5.2
3.5.1
3.5.0
3.4.74
retired
3.4.73
3.4.72
3.4.71
3.4.70
3.4.69
3.4.68
3.4.67
3.4.66
3.4.65
3.4.64
3.4.63
3.4.62
3.4.61
3.4.60
3.4.59
3.4.58
3.4.57
3.4.56
3.4.55
3.4.54
3.4.53
3.4.52
3.4.51
3.4.50
3.4.49
3.4.48
3.4.47
3.4.46
3.4.45
3.4.44
3.4.43
3.4.42
3.4.41
3.4.40
3.4.39
3.4.38
3.4.37
3.4.36
3.4.35
3.4.34
3.4.33
3.4.32
3.4.31
3.4.30
3.4.29
3.4.28
3.4.27
3.4.26
3.4.25
3.4.24
3.4.23
3.4.22
3.4.21
3.4.20
3.4.19
3.4.18
3.4.17
3.4.16
3.4.15
3.4.14
3.4.13
3.4.12
3.4.11
3.4.10
3.4.9
3.4.8
3.4.7
3.4.6
3.4.5
3.4.4
3.4.3
3.4.2
3.4.1
3.4.0
3.3.3
3.3.2
3.3.1
3.3.0
3.2.6
3.2.5
3.2.4
3.2.3
3.2.2
3.2.1
3.2.0
3.1.8
3.1.7
3.1.6
3.1.5
3.1.4
3.1.3
3.1.2
3.1.1
3.1.0
3.0.16
3.0.15
3.0.14
3.0.13
3.0.12
3.0.11
3.0.10
3.0.9
3.0.8
3.0.7
3.0.6
3.0.5
3.0.4
3.0.3
3.0.2
3.0.1
3.0.0
3.0.0-rc.46
3.0.0-rc.45
3.0.0-rc.44
3.0.0-rc.43
3.0.0-rc.42
3.0.0-rc.41
3.0.0-rc.40
3.0.0-rc.39
3.0.0-rc.38
3.0.0-rc.37
3.0.0-rc.36
3.0.0-rc.35
3.0.0-rc.34
3.0.0-rc.33
3.0.0-rc.32
3.0.0-rc.31
3.0.0-rc.29
3.0.0-rc.28
3.0.0-rc.27
3.0.0-rc.26
3.0.0-rc.25
3.0.0-rc.24
3.0.0-rc.23
3.0.0-rc.22
3.0.0-rc.21
3.0.0-rc.20
3.0.0-rc.19
3.0.0-rc.18
3.0.0-rc.17
3.0.0-rc.16
3.0.0-rc.15
3.0.0-rc.14
3.0.0-rc.13
3.0.0-rc.12
3.0.0-rc.11
3.0.0-rc.10
3.0.0-rc.9
3.0.0-rc.8
3.0.0-rc.7
3.0.0-rc.6
3.0.0-rc.5
3.0.0-rc.4
3.0.0-rc.3
3.0.0-rc.1
3.0.0-rc.0
2.21.15
2.21.14
2.21.13
2.21.12
2.21.11
2.21.10
2.21.9
2.21.8
2.21.7
2.21.6
2.21.5
2.21.4
2.21.3
2.21.2
2.21.1
2.21.0
2.20.3
2.20.2
2.20.1
2.20.0
2.19.14
2.19.13
2.19.12
2.19.11
2.19.10
2.19.9
2.19.8
2.19.7
2.19.6
2.19.5
2.19.4
2.19.3
retired
2.19.2
retired
2.19.1
retired
2.19.0
retired
2.18.2
2.18.1
2.18.0
2.17.24
2.17.23
2.17.22
2.17.21
2.17.20
2.17.19
2.17.18
2.17.17
2.17.16
2.17.15
2.17.14
2.17.13
2.17.12
2.17.11
2.17.10
2.17.9
2.17.8
2.17.7
2.17.6
2.17.5
2.17.4
2.17.3
2.17.2
2.17.1
2.17.0
2.16.1
2.16.0
2.15.20
2.15.19
2.15.18
2.15.17
2.15.16
2.15.15
2.15.14
2.15.13
2.15.12
2.15.11
2.15.10
2.15.9
2.15.8
2.15.7
2.15.6
2.15.5
2.15.4
2.15.2
2.15.1
2.15.0
2.14.21
2.14.20
2.14.19
2.14.18
2.14.17
2.14.16
2.14.15
2.14.14
2.14.13
2.14.12
2.14.11
2.14.10
2.14.9
2.14.8
2.14.7
2.14.6
2.14.5
2.14.4
2.14.3
2.14.2
2.14.1
2.14.0
2.13.4
retired
2.13.3
2.13.2
2.13.1
2.13.0
2.12.1
2.12.0
2.11.11
2.11.10
2.11.9
2.11.8
2.11.7
2.11.6
2.11.5
2.11.4
2.11.3
2.11.2
2.11.1
2.11.0
2.11.0-rc.3
2.11.0-rc.2
2.11.0-rc.1
2.11.0-rc.0
2.10.2
2.10.1
2.10.0
2.9.29
2.9.28
2.9.27
2.9.26
2.9.25
2.9.24
2.9.23
2.9.22
2.9.21
2.9.20
2.9.19
2.9.18
2.9.17
2.9.16
2.9.15
2.9.14
2.9.13
2.9.12
2.9.11
2.9.10
2.9.9
2.9.8
2.9.7
2.9.6
2.9.5
2.9.4
2.9.3
2.9.2
2.9.1
2.9.0
2.8.1
2.8.0
2.7.1
2.7.0
2.6.31
2.6.30
2.6.29
2.6.28
2.6.27
2.6.26
2.6.25
2.6.24
2.6.23
2.6.22
2.6.21
2.6.20
2.6.19
2.6.18
2.6.17
2.6.16
2.6.15
2.6.14
2.6.13
2.6.11
2.6.10
2.6.9
2.6.8
2.6.7
2.6.6
2.6.5
2.6.4
2.6.3
2.6.2
2.6.1
2.6.0
2.5.16
2.5.15
2.5.14
2.5.13
2.5.12
2.5.11
2.5.10
2.5.9
2.5.8
2.5.7
2.5.6
2.5.5
2.5.4
2.5.3
2.5.2
2.5.1
2.5.0
2.5.0-rc.6
2.5.0-rc.5
2.5.0-rc.4
2.5.0-rc.3
2.5.0-rc.2
2.5.0-rc.1
2.5.0-rc.0
2.4.30
2.4.29
2.4.28
2.4.27
2.4.26
2.4.25
2.4.24
2.4.23
2.4.22
2.4.21
2.4.20
2.4.19
2.4.18
2.4.17
2.4.16
2.4.15
2.4.14
2.4.13
2.4.12
2.4.11
2.4.10
2.4.9
2.4.8
2.4.7
2.4.6
2.4.5
2.4.4
2.4.3
2.4.2
2.4.1
2.4.0
2.3.0
2.2.0
2.1.0
2.0.0
2.0.0-rc.15
2.0.0-rc.14
2.0.0-rc.13
2.0.0-rc.12
2.0.0-rc.11
2.0.0-rc.10
2.0.0-rc.9
2.0.0-rc.8
2.0.0-rc.7
2.0.0-rc.6
2.0.0-rc.5
2.0.0-rc.4
2.0.0-rc.3
2.0.0-rc.2
2.0.0-rc.1
2.0.0-rc.0
2.0.0-pre.8
2.0.0-pre.7
2.0.0-pre.6
2.0.0-pre.5
2.0.0-pre.4
2.0.0-pre.3
2.0.0-pre.2
2.0.0-pre.1
2.0.0-pre.0
1.53.3
1.53.2
1.53.0
1.52.0-rc.22
1.52.0-rc.21
1.52.0-rc.20
1.52.0-rc.19
1.52.0-rc.18
1.52.0-rc.17
1.52.0-rc.16
1.52.0-rc.15
1.52.0-rc.14
1.52.0-rc.13
1.52.0-rc.12
1.52.0-rc.11
1.52.0-rc.10
1.52.0-rc.9
1.52.0-rc.8
1.52.0-rc.7
1.52.0-rc.6
1.52.0-rc.5
1.52.0-rc.4
1.52.0-rc.3
1.52.0-rc.2
1.52.0-rc.1
1.52.0-rc.0
1.51.2
1.51.1
retired
1.51.0
1.50.21
1.50.20
1.50.19
1.50.18
1.50.17
1.50.16
1.50.15
1.50.14
1.50.13
1.50.12
1.50.11
1.50.10
1.50.9
1.50.8
1.50.7
1.50.6
1.50.5
1.50.4
1.50.3
1.50.2
1.50.1
1.50.0
1.49.0
1.48.0-rc.30
1.48.0-rc.29
1.48.0-rc.28
1.48.0-rc.27
1.48.0-rc.26
1.48.0-rc.25
1.48.0-rc.24
1.48.0-rc.23
1.48.0-rc.22
1.48.0-rc.21
1.48.0-rc.20
1.48.0-rc.19
1.48.0-rc.18
1.48.0-rc.17
1.48.0-rc.16
1.48.0-rc.15
1.48.0-rc.14
1.48.0-rc.13
1.48.0-rc.12
1.48.0-rc.11
1.48.0-rc.10
1.48.0-rc.9
1.48.0-rc.8
1.48.0-rc.7
1.48.0-rc.6
1.48.0-rc.5
1.48.0-rc.4
1.48.0-rc.3
1.48.0-rc.2
1.48.0-rc.1
1.48.0-rc.0
1.47.12
1.47.11
1.47.10
1.47.9
1.47.8
1.47.7
1.47.6
1.47.5
1.47.4
1.47.3
1.47.2
1.47.1
1.47.0
1.46.13
1.46.12
1.46.11
1.46.10
1.46.9
1.46.8
1.46.7
1.46.6
1.46.5
1.46.4
1.46.3
1.46.2
1.46.1
1.46.0
1.45.0-rc9
1.45.0-rc8
1.45.0-rc7
1.45.0-rc6
1.45.0-rc5
1.45.0-rc4
1.45.0-rc3
1.45.0-rc20
1.45.0-rc2
1.45.0-rc19
1.45.0-rc18
1.45.0-rc17
1.45.0-rc16
1.45.0-rc15
1.45.0-rc14
1.45.0-rc13
1.45.0-rc12
1.45.0-rc11
1.45.0-rc10
1.45.0-rc1
1.45.0-rc0
1.44.13
1.44.12
1.44.11
1.44.10
1.44.9
1.44.8
1.44.7
1.44.6
1.44.5
1.44.4
1.44.3
1.44.2
1.44.1
1.44.0
1.43.12
1.43.11
1.43.10
1.43.9
1.43.8
1.43.7
1.43.6
1.43.5
1.43.4
1.43.3
1.43.2
1.43.1
1.43.0
1.42.0
1.41.12
1.41.11
1.41.10
1.41.9
1.41.8
1.41.7
1.41.6
1.41.5
1.41.4
1.41.3
1.41.2
1.41.1
1.41.0
1.40.0
1.39.7
1.39.6
1.39.5
1.39.4
1.39.3
1.39.2
1.39.1
1.39.0
1.38.0
1.37.2
1.37.1
1.37.0
1.36.22
1.36.21
1.36.19
1.36.18
1.36.17
1.36.16
1.36.15
1.36.14
1.36.13
1.36.12
1.36.11
1.36.10
1.36.9
1.36.8
1.36.7
1.36.6
1.36.5
1.36.4
1.36.3
1.36.2
1.36.0
1.35.1
1.35.0
1.34.9
1.34.8
1.34.7
1.34.6
1.34.5
1.34.4
1.34.3
1.34.2
1.34.1
1.34.0
1.33.0
1.32.2
1.32.1
1.32.0
1.31.1
1.31.0
1.30.2
1.30.1
1.29.0-rc1
1.29.0-rc0
1.28.1
1.28.0
1.27.1
1.27.0
1.26.13
1.26.12
1.26.11
1.26.10
1.26.9
1.26.8
1.26.7
1.26.6
1.26.5
1.26.4
1.26.2
1.26.1
1.26.0
1.25.8
1.25.7
1.25.6
1.25.5
1.25.4
1.25.3
1.25.2
1.25.1
1.25.0
1.24.2
1.24.1
1.24.0
1.23.3
1.23.2
1.23.1
1.23.0
1.22.1
1.22.0
1.20.1
1.20.0
1.19.1
1.19.0
1.18.1
1.18.0
1.17.1
1.17.0
1.16.2
1.15.1
1.15.0
1.14.0
1.13.4
1.13.3
1.13.2
1.13.1
1.13.0
1.12.0
1.11.1
1.11.0
1.10.0
1.9.0
1.8.0
1.7.0
1.6.8
1.6.7
1.6.6
1.6.5
1.6.4
1.6.3
1.6.2
1.6.1
1.6.0
1.5.1
1.5.0
1.4.1
1.4.0
1.3.1
1.3.0
1.2.1
1.2.0
1.1.3
1.1.2
1.1.0
1.0.3
1.0.2
1.0.1
1.0.0
0.13.1
0.13.0
0.12.0
0.10.0
0.9.1
0.9.0
0.8.0
0.7.0
0.6.5
0.6.4
0.6.3
0.6.2
0.6.1
0.6.0
0.5.2
0.5.1
0.5.0
0.4.0
0.3.0
0.2.0
0.1.9
0.1.8
0.1.3
0.1.1
0.1.0
A declarative, extensible framework for building Elixir applications.
Security advisory:
This version has known vulnerabilities.
View advisories
Current section
Files
Jump to
Current section
Files
lib/ash/flow/template.ex
defmodule Ash.Flow.Template do
@moduledoc """
Helpers for working with Ash.Flow templates.
At first glance it would seem that all of this could be replaced by some calls to
`Macro.prewalk` but that is unfortunately not the case. We don't traverse through structs,
and in some cases we do things like return ranges/merge maps that require having the entire
nested part of the template, i.e `{:_merge, [list, of, maps]}` has to get the fully handled
list of maps, and so has to call itself.
"""
def is_template?(value) when is_map(value) do
Enum.any?(value, fn {key, value} ->
is_template?(key) || is_template?(value)
end)
end
def is_template?(value) when is_list(value) do
Enum.any?(value, &is_template?/1)
end
def is_template?({:_path, _, _}), do: true
def is_template?({:_merge, _}), do: true
def is_template?({:_expr, expr}) do
not is_nil(Ash.Filter.find(expr, &is_template?/1))
end
def is_template?({:_result, _}), do: true
def is_template?({:_element, _}), do: true
def is_template?(tuple) when is_tuple(tuple) do
tuple
|> Tuple.to_list()
|> Enum.any?(&is_template?/1)
end
def is_template?(_), do: false
def remap_result_references(action_input, prefix) do
do_remap_result_references(action_input, prefix)
end
defp do_remap_result_references(action_input, prefix)
when is_map(action_input) and not is_struct(action_input) do
Map.new(action_input, fn {key, value} ->
new_key = do_remap_result_references(key, prefix)
new_val = do_remap_result_references(value, prefix)
{new_key, new_val}
end)
end
defp do_remap_result_references(action_input, prefix) when is_list(action_input) do
Enum.map(action_input, &do_remap_result_references(&1, prefix))
end
defp do_remap_result_references({:_path, value, path}, prefix) do
{:_path, do_remap_result_references(value, prefix), do_remap_result_references(path, prefix)}
end
defp do_remap_result_references({:_merge, items}, prefix) do
{:_merge, do_remap_result_references(items, prefix)}
end
defp do_remap_result_references({:_expr, expr}, prefix) do
{:_expr, Ash.Filter.walk_filter_template(expr, &do_remap_result_references(&1, prefix))}
end
defp do_remap_result_references({:_result, step}, prefix) when is_function(prefix) do
{:_result, prefix.(step)}
end
defp do_remap_result_references({:_result, step}, prefix) do
{:_result, [prefix | List.wrap(step)]}
end
defp do_remap_result_references({:_element, step}, prefix) when is_function(prefix) do
{:_element, prefix.(step)}
end
defp do_remap_result_references({:_element, step}, prefix) do
{:_element, [prefix | List.wrap(step)]}
end
defp do_remap_result_references(action_input, input) when is_tuple(action_input) do
List.to_tuple(do_remap_result_references(Tuple.to_list(action_input), input))
end
defp do_remap_result_references(other, _), do: other
def set_dependent_values(action_input, input) do
do_set_dependent_values(action_input, input)
end
defp do_set_dependent_values(action_input, input)
when is_map(action_input) and not is_struct(action_input) do
Map.new(action_input, fn {key, value} ->
new_key = do_set_dependent_values(key, input)
new_val = do_set_dependent_values(value, input)
{new_key, new_val}
end)
end
defp do_set_dependent_values(action_input, input) when is_list(action_input) do
Enum.map(action_input, &do_set_dependent_values(&1, input))
end
defp do_set_dependent_values({:_path, value, path}, input) do
{:_path, do_set_dependent_values(value, input), do_set_dependent_values(path, input)}
end
defp do_set_dependent_values({:_expr, expr}, input) do
{:_expr, Ash.Filter.walk_filter_template(expr, &do_set_dependent_values(&1, input))}
end
defp do_set_dependent_values({:_merge, items}, input) do
items
|> Enum.map(&do_set_dependent_values(&1, input))
|> Enum.reject(&is_nil/1)
|> Enum.reduce(%{}, &Map.merge(&2, &1))
end
defp do_set_dependent_values({:_result, step}, input) do
get_in(input, [:results, step])
end
defp do_set_dependent_values({:_element, step}, input) do
get_in(input, [:elements, step])
end
defp do_set_dependent_values({:_range, start, finish}, input) do
do_set_dependent_values(start, input)..do_set_dependent_values(finish, input)
end
defp do_set_dependent_values(action_input, input) when is_tuple(action_input) do
List.to_tuple(do_set_dependent_values(Tuple.to_list(action_input), input))
end
defp do_set_dependent_values(other, _), do: other
def arg_refs(input) when is_map(input) do
Enum.flat_map(input, &arg_refs/1)
end
def arg_refs(input) when is_list(input) do
Enum.flat_map(input, &arg_refs/1)
end
def arg_refs({:_expr, expr}) do
list_expr_refs(
expr,
fn
{:_arg, _} ->
true
_ ->
false
end
)
|> Enum.map(&elem(&1, 1))
end
def arg_refs({:_arg, name}) do
[name]
end
def arg_refs(input) when is_tuple(input) do
input
|> Tuple.to_list()
|> Enum.flat_map(&arg_refs/1)
end
def arg_refs(_), do: []
def element_refs(input) when is_map(input) do
Enum.flat_map(input, &element_refs/1)
end
def element_refs(input) when is_list(input) do
Enum.flat_map(input, &element_refs/1)
end
def element_refs({:_expr, expr}) do
list_expr_refs(
expr,
fn
{:_element, _} ->
true
_ ->
false
end
)
|> Enum.map(&elem(&1, 1))
end
def element_refs({:_element, name}) do
[name]
end
def element_refs(input) when is_tuple(input) do
input
|> Tuple.to_list()
|> Enum.flat_map(&element_refs/1)
end
def element_refs(_), do: []
def result_refs(input) when is_map(input) do
Enum.flat_map(input, &result_refs/1)
end
def result_refs(input) when is_list(input) do
Enum.flat_map(input, &result_refs/1)
end
def result_refs({:_expr, expr}) do
list_expr_refs(
expr,
fn
{:_result, _} ->
true
_ ->
false
end
)
|> Enum.map(&elem(&1, 1))
end
def result_refs({:_result, name}) do
[name]
end
def result_refs(input) when is_tuple(input) do
input
|> Tuple.to_list()
|> Enum.flat_map(&result_refs/1)
end
def result_refs(_), do: []
defp list_expr_refs(expression, matcher) do
expression
|> do_list_expr_refs(matcher)
|> Enum.uniq()
end
defp do_list_expr_refs(list, matcher) when is_list(list) do
Enum.flat_map(list, &do_list_expr_refs(&1, matcher))
end
defp do_list_expr_refs({key, value}, matcher) when is_atom(key) do
if matcher.({key, value}) do
[{key, value}]
else
do_list_expr_refs(value, matcher)
end
end
defp do_list_expr_refs(expression, matcher) do
case expression do
%Ash.Query.BooleanExpression{left: left, right: right} ->
do_list_expr_refs(left, matcher) ++ do_list_expr_refs(right, matcher)
%Ash.Query.Not{expression: not_expr} ->
do_list_expr_refs(not_expr, matcher)
%{__predicate__?: _, left: left, right: right} ->
do_list_expr_refs(left, matcher) ++
do_list_expr_refs(right, matcher)
%{__predicate__?: _, arguments: args} ->
Enum.flat_map(args, &do_list_expr_refs(&1, matcher))
%Ash.Query.Call{args: args} ->
args
|> Enum.flat_map(&do_list_expr_refs(&1, matcher))
v ->
if matcher.(v) do
[v]
else
[]
end
end
end
def handle_input_template(action_input, input) do
{val, deps} = do_handle_input_template(action_input, input)
{val, Enum.uniq(deps)}
end
defp do_handle_input_template({:_expr, expr}, input) do
{new_expr, deps} = do_handle_input_template(expr, input)
{{:_expr, new_expr}, deps}
end
defp do_handle_input_template(
%Ash.Query.BooleanExpression{left: left, right: right} = expr,
input
) do
{new_left, left_deps} = do_handle_input_template(left, input)
{new_right, right_deps} = do_handle_input_template(right, input)
{%{expr | left: new_left, right: new_right}, left_deps ++ right_deps}
end
defp do_handle_input_template(%Ash.Query.Not{expression: expression} = not_expr, input) do
{new_expr, deps} = do_handle_input_template(expression, input)
{%{not_expr | expression: new_expr}, deps}
end
defp do_handle_input_template(%{__predicate__?: _, left: left, right: right} = pred, input) do
{new_left, left_deps} = do_handle_input_template(left, input)
{new_right, right_deps} = do_handle_input_template(right, input)
{%{pred | left: new_left, right: new_right}, left_deps ++ right_deps}
end
defp do_handle_input_template(%{__predicate__?: _, arguments: arguments} = func, input) do
{args, deps} =
Enum.reduce(arguments, {[], []}, fn arg, {args, deps} ->
{new_arg, new_deps} = do_handle_input_template(arg, input)
{[new_arg | args], deps ++ new_deps}
end)
{%{func | arguments: Enum.reverse(args)}, deps}
end
defp do_handle_input_template(%Ash.Query.Call{args: arguments} = call, input) do
{args, deps} =
Enum.reduce(arguments, {[], []}, fn arg, {args, deps} ->
{new_arg, new_deps} = do_handle_input_template(arg, input)
{[new_arg | args], deps ++ new_deps}
end)
{%{call | args: Enum.reverse(args)}, deps}
end
defp do_handle_input_template(action_input, input)
when is_map(action_input) and not is_struct(action_input) do
Enum.reduce(action_input, {%{}, []}, fn {key, value}, {acc, deps} ->
{new_key, key_deps} = do_handle_input_template(key, input)
{new_val, val_deps} = do_handle_input_template(value, input)
{Map.put(acc, new_key, new_val), deps ++ key_deps ++ val_deps}
end)
end
defp do_handle_input_template(action_input, input) when is_list(action_input) do
{new_items, deps} =
Enum.reduce(action_input, {[], []}, fn item, {items, deps} ->
{new_item, new_deps} = do_handle_input_template(item, input)
{[new_item | items], new_deps ++ deps}
end)
{Enum.reverse(new_items), deps}
end
defp do_handle_input_template({:_path, value, path}, input) do
{new_value, value_deps} = do_handle_input_template(value, input)
{new_path, path_deps} = do_handle_input_template(path, input)
{{:_path, new_value, new_path}, value_deps ++ path_deps}
end
defp do_handle_input_template({:_merge, items}, input) do
{new_items, deps} =
Enum.reduce(items, {[], []}, fn item, {items, deps} ->
{new_item, new_deps} = do_handle_input_template(item, input)
{[new_item | items], new_deps ++ deps}
end)
{{:_merge, new_items}, deps}
end
defp do_handle_input_template({:_arg, name}, input) do
{Map.get(input, name) || Map.get(input, to_string(name)), []}
end
defp do_handle_input_template({:_result, step}, _input) do
{{:_result, step}, [{:_result, step}]}
end
defp do_handle_input_template(action_input, input) when is_tuple(action_input) do
{list, deps} = do_handle_input_template(Tuple.to_list(action_input), input)
{List.to_tuple(list), deps}
end
defp do_handle_input_template(other, _), do: {other, []}
end