This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| @spec audit_fun(struct(), Macro.Env.t()) :: struct() | |
| def audit_fun(r, e) do | |
| r |> struct([{@key, payload(r, e)}]) | |
| end | |
| @spec payload(struct(), Macro.Env) :: trail_t() | |
| def payload(r, e), do: {r, e.file, e.line} |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| @key :__audit_trail__ | |
| @enabled? Application.compile_env(:audit, :enabled?, false) | |
| @type file_t :: binary() | |
| @type line_t :: non_neg_integer() | |
| @type trail_t :: {struct(), file_t(), line_t()} | |
| @type change_t :: {struct(), trail_t()} |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| @empty [false, "", nil, [], 0, 0.0] | |
| @spec empty?(any()) :: boolean() | |
| def empty?(value) when value in @empty, do: true | |
| def empty?(value) when is_list(value), do: Enum.all?(value, &empty?/1) | |
| def empty?(value) when is_tuple(value), do: value |> Tuple.to_list() |> empty?() | |
| def empty?(value) when is_struct(value), do: value |> Map.from_struct() |> empty?() | |
| def empty?(value) when is_map(value), do: value |> Map.values() |> empty?() | |
| def empty?(_), do: false |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| @spec delta_simple(path(), term(), term()) :: [delta()] | |
| defp delta_simple(_path, a, b) when a == b, do: [] | |
| defp delta_simple(path, a, b) do | |
| cond do | |
| empty?(a) -> [{path, {:add, b}}] | |
| empty?(b) -> [{path, {:delete, a}}] | |
| true -> [{path, {:update, a, b}}] | |
| end | |
| end |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| @spec delta_tuple(path(), tuple(), tuple()) :: [delta()] | |
| defp delta_tuple(path, a, b) when tuple_size(a) != tuple_size(b), do: delta_simple(path, a, b) | |
| defp delta_tuple(path, a, b), do: delta_list(path, Tuple.to_list(a), Tuple.to_list(b)) |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| @spec delta_list(path(), list(), list()) :: [delta()] | |
| defp delta_list(path, as, bs) when length(as) != length(bs), do: delta_simple(path, as, bs) | |
| defp delta_list(path, as, bs) do | |
| as | |
| |> indexed_zip(bs) | |
| |> Enum.flat_map(fn {i, {a, b}} -> delta([i | path], a, b) end) | |
| end | |
| def indexed_zip(as, bs, i \\ 0) |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| @spec delta_map(path(), map(), map()) :: [delta()] | |
| def delta_map(path, a, b) do | |
| a_keys = MapSet.new(Map.keys(a)) | |
| b_keys = MapSet.new(Map.keys(b)) | |
| common = MapSet.intersection(a_keys, b_keys) | |
| a_only = a_keys |> MapSet.difference(common) | |
| b_only = b_keys |> MapSet.difference(common) | |
| Enum.flat_map(common, fn key -> delta([key | path], a[key], b[key]) end) ++ | |
| Enum.flat_map(a_only, fn key -> [{[key | path], {:delete, a[key]}}] end) ++ |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| @spec delta_struct(path(), struct(), struct()) :: delta_spec() | |
| def delta_struct(path, %a_s{} = a, %b_s{} = b) when a_s != b_s, do: delta_simple(path, a, b) | |
| def delta_struct(path, a, b), do: delta_map(path, Map.from_struct(a), Map.from_struct(b)) |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| @spec delta(path(), any(), any()) :: delta_spec() | |
| defp delta(path, a, b) when is_struct(a) and is_struct(b), do: delta_struct(path, a, b) | |
| defp delta(path, a, b) when is_map(a) and is_map(b), do: delta_map(path, a, b) | |
| defp delta(path, a, b) when is_list(a) and is_list(b), do: delta_list(path, a, b) | |
| defp delta(path, a, b) when is_tuple(a) and is_tuple(b), do: delta_tuple(path, a, b) | |
| defp delta(path, a, b), do: delta_simple(path, a, b) |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| @spec delta(any(), any()) :: delta_spec() | |
| def delta(a, b) do | |
| [] | |
| |> delta(a, b) | |
| |> List.flatten() | |
| |> Enum.map(fn {path, element} -> {Enum.reverse(path), element} end) | |
| |> Enum.sort_by(fn {path, _} -> {length(path), path} end) | |
| end |