Jsonpatch (Jsonpatch v1.0.0) View Source

A implementation of RFC 6902 in pure Elixir.

The patch can be a single change or a list of things that shall be changed. Therefore a list or a single JSON patch can be provided. Every patch belongs to a certain operation which influences the usage.

According to RFC 6901 escaping of / and ~ is done by using ~1 for / and ~0 for ~.

Link to this section Summary

Types

Describe an error that occured while patching.

t()

A valid Jsonpatch operation by RFC 6902

Functions

Apply a Jsonpatch or a list of Jsonpatches to a map or struct. The whole patch will not be applied when any path is invalid or any other error occured. When a list is provided, the operations are applied in the order as they appear in the list.

Apply a Jsonpatch or a list of Jsonpatches to a map or struct. In case of an error it will raise an exception. When a list is provided, the operations are applied in the order as they appear in the list.

Creates a patch from the difference of a source map to a destination map or list.

Link to this section Types

Specs

error() :: {:error, :invalid_path | :invalid_index | :test_failed, bitstring()}

Describe an error that occured while patching.

Specs

A valid Jsonpatch operation by RFC 6902

Link to this section Functions

Link to this function

apply_patch(json_patch, target, opts \\ [])

View Source

Specs

apply_patch(t() | [t()], map(), keyword()) :: {:ok, map()} | error()

Apply a Jsonpatch or a list of Jsonpatches to a map or struct. The whole patch will not be applied when any path is invalid or any other error occured. When a list is provided, the operations are applied in the order as they appear in the list.

Atoms are never garbage collected. Therefore, Jsonpatch works by default only with maps which used binary strings as key. This behaviour can be controlled via the :keys option.

Options

  • :keys - controls how parts of paths are decoded. Possible values:
    • :strings (default) - decodes parts of paths as binary strings,
    • :atoms - parts of paths are converted to atoms using String.to_atom/1,
    • :atoms! - parts of paths are converted to atoms using String.to_existing_atom/1

Examples

iex> patch = [
...> %Jsonpatch.Operation.Add{path: "/age", value: 33},
...> %Jsonpatch.Operation.Replace{path: "/hobbies/0", value: "Elixir!"},
...> %Jsonpatch.Operation.Replace{path: "/married", value: true},
...> %Jsonpatch.Operation.Remove{path: "/hobbies/2"},
...> %Jsonpatch.Operation.Remove{path: "/hobbies/1"},
...> %Jsonpatch.Operation.Copy{from: "/name", path: "/surname"},
...> %Jsonpatch.Operation.Move{from: "/home", path: "/work"},
...> %Jsonpatch.Operation.Test{path: "/name", value: "Bob"}
...> ]
iex> target = %{"name" => "Bob", "married" => false, "hobbies" => ["Sport", "Elixir", "Football"], "home" => "Berlin"}
iex> Jsonpatch.apply_patch(patch, target)
{:ok, %{"name" => "Bob", "married" => true, "hobbies" => ["Elixir!"], "age" => 33, "surname" => "Bob", "work" => "Berlin"}}

iex> # Patch will not be applied if test fails. The target will not be changed.
iex> patch = [
...> %Jsonpatch.Operation.Add{path: "/age", value: 33},
...> %Jsonpatch.Operation.Test{path: "/name", value: "Alice"}
...> ]
iex> target = %{"name" => "Bob", "married" => false, "hobbies" => ["Sport", "Elixir", "Football"], "home" => "Berlin"}
iex> Jsonpatch.apply_patch(patch, target)
{:error, :test_failed, "Expected value 'Alice' at '/name'"}
Link to this function

apply_patch!(json_patch, target, opts \\ [])

View Source

Specs

apply_patch!(t() | [t()], map(), keyword()) :: map()

Apply a Jsonpatch or a list of Jsonpatches to a map or struct. In case of an error it will raise an exception. When a list is provided, the operations are applied in the order as they appear in the list.

(See Jsonpatch.apply_patch/2 for more details)

Link to this function

diff(source, destination)

View Source

Specs

diff(maybe_improper_list() | map(), maybe_improper_list() | map()) :: [t()]

Creates a patch from the difference of a source map to a destination map or list.

Examples

iex> source = %{"name" => "Bob", "married" => false, "hobbies" => ["Elixir", "Sport", "Football"]}
iex> destination = %{"name" => "Bob", "married" => true, "hobbies" => ["Elixir!"], "age" => 33}
iex> Jsonpatch.diff(source, destination)
[
  %Jsonpatch.Operation.Replace{path: "/married", value: true},
  %Jsonpatch.Operation.Remove{path: "/hobbies/2"},
  %Jsonpatch.Operation.Remove{path: "/hobbies/1"},
  %Jsonpatch.Operation.Replace{path: "/hobbies/0", value: "Elixir!"},
  %Jsonpatch.Operation.Add{path: "/age", value: 33}
]