GuardedStruct.Diff (GuardedStruct v0.1.0-beta.1)

Copy Markdown View Source

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(struct, diff)

@spec apply(struct() | map(), map()) :: struct() | map()

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(a, b)

@spec diff(struct() | map() | any(), struct() | map() | any()) ::
  map() | :not_comparable

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.

equal?(a, b)

@spec equal?(any(), any()) :: boolean()

Returns true if the two structs are equal field-by-field (same as diff(a, b) == %{} but skips work for unchanged fields).