Field-level diffs between two GuardedStruct instances.
iex> GuardedStruct.Diff.diff(
...> %User{name: "Alice", age: 30, role: "admin"},
...> %User{name: "Alice", age: 31, role: "user"}
...> )
%{
age: {:changed, 30, 31},
role: {:changed, "admin", "user"}
}Equal fields are omitted. Nested struct fields recurse — name: %User{} → %User{}
produces a nested map, not a :changed tuple.
Useful for audit logs, CRM history, and "what changed" UIs.
Summary
Functions
Apply a diff to a struct, returning the result of applying the new values.
Diff two structs of the same module. Returns a map keyed by field name with values of one of
Returns true if the two structs are equal field-by-field (same as
diff(a, b) == %{} but skips work for unchanged fields).
Functions
Apply a diff to a struct, returning the result of applying the new values.
iex> User.builder(%{name: "Alice", age: 30}) |> elem(1) |> GuardedStruct.Diff.apply(%{age: {:changed, 30, 31}})
%User{name: "Alice", age: 31}Nested struct diffs apply recursively. :changed tuples replace the field
with their new value. Unknown keys in the diff are silently ignored.
Diff two structs of the same module. Returns a map keyed by field name with values of one of:
{:changed, old, new}— primitive value differs%{...}— nested struct, recursively diffed (only if there ARE changes)
Equal fields are omitted from the result.
Returns :not_comparable if the two values are not the same struct module.
Returns true if the two structs are equal field-by-field (same as
diff(a, b) == %{} but skips work for unchanged fields).