Skip to content

Calculates the difference between two (nested) maps, and returns a map representing the patch of changes.

License

Notifications You must be signed in to change notification settings

andre1sk/elixir_map_diff

 
 

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

22 Commits
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

MapDiff

hex.pm version Build Status Inline docs

Calculates the difference between two (nested) maps.

The idea is very simple: One of four things can happen to each key in a map:

  • It remains the same: :equal
  • It was not in the original map, but it is in the new one: :added
  • It was in the original map, but is no longer in the new one: :removed
  • It is in both maps, but its value changed.

For the fourth variant, MapDiff.diff/2 returns :primitive_change if the value under the key was 'simply changed', and :map_change if in both arguments this value itself is a map, which means that MapDiff.diff/2 was called on it recursively.

"""

@doc """ This is the single function that MapDiff currently exports.

It returns a 'patch', which is a map describing the changes between map_a and map_b.

Examples

If the (nested) map is still the same, it is considered :equal:

iex> MapDiff.diff(%{my: 1}, %{my: 1})
%{changed: :equal, value: %{my: 1}}

When a key disappears, it is considered :removed:

iex> MapDiff.diff(%{a: 1}, %{})
%{changed: :map_change, value: %{a: %{changed: :removed, value: 1}}}

When a key appears, it is considered :added:

iex> MapDiff.diff(%{}, %{b: 2})
%{changed: :map_change, value: %{b: %{changed: :added, value: 2}}}

When the value of a key changes (and the old nor the new value was a map), then this is considered a :primitive_change.

iex> MapDiff.diff(%{b: 3}, %{b: 2})
%{changed: :map_change,
  value: %{b: %{added: 2, changed: :primitive_change, removed: 3}}}
iex> MapDiff.diff(%{val: 3}, %{val: %{}})
%{changed: :map_change,
  value: %{val: %{changed: :primitive_change, added: %{}, removed: 3}}}

When the value of a key changes, and the old and new values are both maps, then this is considered a :map_change that can be parsed recursively.

iex> MapDiff.diff(%{a: %{}}, %{a: %{b: 1}})
%{changed: :map_change,
  value: %{a: %{changed: :map_change,
  value: %{b: %{changed: :added, value: 1}}}}}

A more complex example, to see what happens with nested maps:

iex> foo = %{a: 1, b: 2, c: %{d: 3, e: 4, f: 5}}
iex> bar = %{a: 1, b: 42, c: %{d: %{something_else: "entirely"}, f: 10}}
iex> MapDiff.diff(foo, bar)
%{changed: :map_change,
  value: %{a: %{changed: :equal, value: 1},
    b: %{added: 42, changed: :primitive_change, removed: 2},
    c: %{changed: :map_change,
      value: %{d: %{added: %{something_else: "entirely"},
      changed: :primitive_change, removed: 3},
    e: %{changed: :removed, value: 4},
    f: %{added: 10, changed: :primitive_change, removed: 5}}}}}

It is also possible to compare two structs of the same kind. MapDiff.diff/2 will add a struct_name field to the output, so you are reminded of the kind of struct whose fields were changed.

For example, suppose you define the following structs:

defmodule Foo do
  defstruct a: 1, b: 2, c: 3
end

defmodule Baz do
  defstruct a: "foo", b: "bar", z: "baz"
end

Then the fields of one Foo struct can be compared to another:

iex> MapDiff.diff(%Foo{}, %Foo{a: 3})
%{changed: :map_change, struct_name: Foo,
  value: %{a: %{added: 3, changed: :primitive_change, removed: 1},
    b: %{changed: :equal, value: 2}, c: %{changed: :equal, value: 3}}}

When comparing two different kinds of structs, this of course results in a :primitive_change, as they are simply considered primitive data types.

iex> MapDiff.diff(%Foo{}, %Bar{})
%{added: %Bar{a: "foo", b: "bar", z: "baz"}, changed: :primitive_change,
  removed: %Foo{a: 1, b: 2, c: 3}}

Installation

The package can be installed by adding map_diff to your list of dependencies in mix.exs:

def deps do
  [{:map_diff, "~> 1.0"}]
end

Documentation can be generated with ExDoc and published on HexDocs. Once published, the docs can be found at https://hexdocs.pm/map_diff.

About

Calculates the difference between two (nested) maps, and returns a map representing the patch of changes.

Resources

License

Stars

Watchers

Forks

Releases

No releases published

Packages

No packages published

Languages

  • Elixir 100.0%