An implementation of RFC 6902 in pure Elixir.
Features:
- Creating a patch by comparing to maps and lists
- Apply patches to maps and lists - supports operations:
- add
- replace
- remove
- copy
- move
- test
- Escaping of "
/" (by "~1") and "~" (by "~0") - Allow usage of
-for appending things to list (Add and Copy operation) - Smart list diffing with
object_hashfor efficient patches on collections with unique identifiers
The package can be installed by adding jsonpatch to your list of dependencies in mix.exs:
def deps do [ {:jsonpatch, "~> 2.2"} ] endThe docs can be found at https://hexdocs.pm/jsonpatch.
iex> source = %{"name" => "Bob", "married" => false, "hobbies" => ["Sport", "Elixir", "Football"]} iex> destination = %{"name" => "Bob", "married" => true, "hobbies" => ["Elixir!"], "age" => 33} iex> Jsonpatch.diff(source, destination) [ %{path: "/married", value: true, op: "replace"}, %{path: "/hobbies/2", op: "remove"}, %{path: "/hobbies/1", op: "remove"}, %{path: "/hobbies/0", value: "Elixir!", op: "replace"}, %{path: "/age", value: 33, op: "add"} ]Use object_hash to generate efficient patches for lists of objects with unique identifiers, producing minimal operations instead of cascading replacements.
iex> original = [ %{id: 1, name: "Alice"}, %{id: 2, name: "Bob"} ] iex> updated = [ %{id: 99, name: "New"}, %{id: 1, name: "Alice"}, %{id: 2, name: "Bob"} ] # Traditional pairwise diff - multiple replace operations # >> Jsonpatch.diff(original, updated) [ %{op: "add", path: "/2", value: %{id: 2, name: "Bob"}} %{op: "replace", path: "/0", value: %{id: 99, name: "New"}}, %{op: "replace", path: "/1", value: %{id: 1, name: "Alice"}}, ] # With object_hash - single add operation iex> Jsonpatch.diff(original, updated, object_hash: fn %{id: id} -> id end) [ %{op: "add", path: "/0", value: %{id: 99, name: "New"}} ]iex> patch = [ %{op: "add", path: "/age", value: 33}, %{op: "replace", path: "/hobbies/0", value: "Elixir!"}, %{op: "replace", path: "/married", value: true}, %{op: "remove", path: "/hobbies/1"}, %{op: "remove", path: "/hobbies/2"} ] iex> target = %{"name" => "Bob", "married" => false, "hobbies" => ["Sport", "Elixir", "Football"]} iex> Jsonpatch.apply_patch(patch, target) {:ok, %{"name" => "Bob", "married" => true, "hobbies" => ["Elixir!"], "age" => 33}}