Current section
Files
Jump to
Current section
Files
lib/jsonpatch/mapper.ex
defmodule Jsonpatch.Mapper do
@moduledoc """
Maps JSON patches between regular Maps and list or a single Jsonpatch.Operation.
"""
@doc """
Turns JSON patches into regular map/s.
## Examples
iex> add_patch_map = %Jsonpatch.Operation.Add{path: "/name", value: "Alice"}
iex> Jsonpatch.Mapper.to_map(add_patch_map)
%{op: "add", path: "/name", value: "Alice"}
iex> add_patch_map = %Jsonpatch.Operation.Add{path: "/name", value: "Alice"}
iex> remove_patch_map = %Jsonpatch.Operation.Remove{path: "/location"}
iex> Jsonpatch.Mapper.to_map([add_patch_map, remove_patch_map])
[%{op: "add", path: "/name", value: "Alice"},
%{op: "remove", path: "/location"}]
"""
@spec to_map(Jsonpatch.t() | list(Jsonpatch.t())) ::
map() | list() | {:error, :invalid}
def to_map(patch)
def to_map(patch_operations) when is_list(patch_operations) do
Enum.map(patch_operations, &prepare/1)
|> Enum.filter(&is_valid/1)
|> Enum.map(&Map.from_struct/1)
end
def to_map(%{} = patch_operation) do
case prepare(patch_operation) do
{:error, _} = error -> error
patch -> patch |> Map.from_struct()
end
end
@doc """
Creates JSON patch struct/s from a single or list maps which represents JSON patches.
## Examples
iex> add_patch_map = %{"op" => "add", "path" => "/name", "value" => "Alice"}
iex> Jsonpatch.Mapper.from_map(add_patch_map)
%Jsonpatch.Operation.Add{path: "/name", value: "Alice"}
iex> unkown_patch_map = %{"op" => "foo", "path" => "/name", "value" => "Alice"}
iex> Jsonpatch.Mapper.from_map(unkown_patch_map)
{:error, :invalid}
"""
@spec from_map(map() | list(map())) ::
list(Jsonpatch.t()) | Jsonpatch.t() | {:error, :invalid}
def from_map(patch)
def from_map(%{} = patch) do
convert_to(patch)
end
def from_map(patch) when is_list(patch) do
Enum.map(patch, &from_map/1)
end
# ===== ===== PRIVATE ===== =====
defp prepare(%Jsonpatch.Operation.Add{} = operation) do
Map.put(operation, :op, "add")
end
defp prepare(%Jsonpatch.Operation.Remove{} = operation) do
Map.put(operation, :op, "remove")
end
defp prepare(%Jsonpatch.Operation.Replace{} = operation) do
Map.put(operation, :op, "replace")
end
defp prepare(%Jsonpatch.Operation.Copy{} = operation) do
Map.put(operation, :op, "copy")
end
defp prepare(%Jsonpatch.Operation.Move{} = operation) do
Map.put(operation, :op, "move")
end
defp prepare(%Jsonpatch.Operation.Test{} = operation) do
Map.put(operation, :op, "test")
end
defp prepare(_) do
{:error, :invalid}
end
defp convert_to(%{"op" => "add", "path" => path, "value" => value}) do
%Jsonpatch.Operation.Add{path: path, value: value}
end
defp convert_to(%{"op" => "remove", "path" => path}) do
%Jsonpatch.Operation.Remove{path: path}
end
defp convert_to(%{"op" => "replace", "path" => path, "value" => value}) do
%Jsonpatch.Operation.Replace{path: path, value: value}
end
defp convert_to(%{"op" => "copy", "from" => from, "path" => path}) do
%Jsonpatch.Operation.Copy{from: from, path: path}
end
defp convert_to(%{"op" => "move", "from" => from, "path" => path}) do
%Jsonpatch.Operation.Move{from: from, path: path}
end
defp convert_to(%{"op" => "test", "path" => path, "value" => value}) do
%Jsonpatch.Operation.Test{path: path, value: value}
end
defp convert_to(_) do
{:error, :invalid}
end
defp is_valid({:error, _}), do: false
defp is_valid(_), do: true
end