-
-
Notifications
You must be signed in to change notification settings - Fork 16
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
feat: Full diff change tracking mode (#18)
- Loading branch information
Showing
24 changed files
with
2,086 additions
and
89 deletions.
There are no files selected for viewing
This file contains 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
This file contains 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
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,18 @@ | ||
defmodule AshPaperTrail.ChangeBuilders.ChangesOnly do | ||
def build_changes(attributes, changeset) do | ||
Enum.reduce(attributes, %{}, &build_attribute_change(&1, changeset, &2)) | ||
end | ||
|
||
def build_attribute_change(attribute, changeset, changes) do | ||
if Ash.Changeset.changing_attribute?(changeset, attribute.name) do | ||
value = Ash.Changeset.get_attribute(changeset, attribute.name) | ||
|
||
{:ok, dumped_value} = | ||
Ash.Type.dump_to_embedded(attribute.type, value, attribute.constraints) | ||
|
||
Map.put(changes, attribute.name, dumped_value) | ||
else | ||
changes | ||
end | ||
end | ||
end |
This file contains 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
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,51 @@ | ||
defmodule AshPaperTrail.ChangeBuilders.FullDiff.EmbeddedChange do | ||
import AshPaperTrail.ChangeBuilders.FullDiff.Helpers | ||
|
||
@moduledoc """ | ||
A simple attribute change will be represented as a map: | ||
%{ created: %{ subject: %{to: "subject"} } } | ||
%{ updated: %{ subject: %{from: "subject", to: "new subject"} } } | ||
%{ unchanged: %{ subject: %{unchanged: "subject"} } } | ||
%{ destroyed: %{ subject: %{unchanged: "subject"} } } | ||
""" | ||
|
||
def build(attribute, changeset) do | ||
dump_data_value(changeset, attribute) | ||
|> embedded_change_map() | ||
end | ||
|
||
def dump_data_value(changeset, attribute) do | ||
data_tuple = | ||
if changeset.action_type == :create do | ||
:not_present | ||
else | ||
case Ash.Changeset.get_data(changeset, attribute.name) do | ||
nil -> | ||
nil | ||
|
||
data -> | ||
dumped_data = dump_value(data, attribute) | ||
uid = unique_id(data, dumped_data) | ||
{uid, dumped_data} | ||
end | ||
end | ||
|
||
value_tuple = | ||
case Ash.Changeset.fetch_change(changeset, attribute.name) do | ||
{:ok, nil} -> | ||
nil | ||
|
||
{:ok, value} -> | ||
dumped_value = dump_value(value, attribute) | ||
uid = unique_id(value, dumped_value) | ||
{uid, dumped_value} | ||
|
||
:error -> | ||
:not_present | ||
end | ||
|
||
{data_tuple, value_tuple} | ||
end | ||
end |
This file contains 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
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,53 @@ | ||
defmodule AshPaperTrail.ChangeBuilders.FullDiff do | ||
@moduledoc """ | ||
Builds a diff of the changeset that is both fairly easy read and includes a complete | ||
representation of the changes mades. | ||
""" | ||
|
||
import AshPaperTrail.ChangeBuilders.FullDiff.Helpers | ||
|
||
alias AshPaperTrail.ChangeBuilders.FullDiff.{ | ||
SimpleChange, | ||
EmbeddedChange, | ||
UnionChange, | ||
ListChange | ||
} | ||
|
||
@doc """ | ||
Return a map of the changes made with a key for each attribute and a value | ||
that is a map representing each change. The structure of map representing the | ||
each change comes in multiple: simple/native, embedded, union, and array of embedded and array of unions. | ||
%{ | ||
subject: %{ from: "subject", to: "new subject" }, | ||
body: { unchanged: "body" } | ||
} | ||
""" | ||
def build_changes(attributes, changeset) do | ||
Enum.reduce(attributes, %{}, fn attribute, changes -> | ||
Map.put( | ||
changes, | ||
attribute.name, | ||
build_attribute_change(attribute, changeset) | ||
) | ||
end) | ||
end | ||
|
||
defp build_attribute_change(%{type: {:array, _}} = attribute, changeset) do | ||
ListChange.build(attribute, changeset) | ||
end | ||
|
||
defp build_attribute_change(attribute, changeset) do | ||
cond do | ||
is_union?(attribute.type) -> | ||
UnionChange.build(attribute, changeset) | ||
|
||
is_embedded?(attribute.type) -> | ||
EmbeddedChange.build(attribute, changeset) | ||
|
||
true -> | ||
SimpleChange.build(attribute, changeset) | ||
end | ||
end | ||
end |
Oops, something went wrong.