Skip to content

Commit

Permalink
Merge pull request #21 from tulinmola/master
Browse files Browse the repository at this point in the history
Add ignore_invalid_paths to patch
  • Loading branch information
corka149 authored Feb 28, 2024
2 parents 26bacd3 + 98e01c2 commit 2671eec
Show file tree
Hide file tree
Showing 3 changed files with 26 additions and 4 deletions.
21 changes: 18 additions & 3 deletions lib/jsonpatch.ex
Original file line number Diff line number Diff line change
Expand Up @@ -50,22 +50,37 @@ defmodule Jsonpatch do
iex> target = %{"name" => "Bob", "married" => false, "hobbies" => ["Sport", "Elixir", "Football"], "home" => "Berlin"}
iex> Jsonpatch.apply_patch(patch, target)
{:error, %Jsonpatch.Error{patch: %{"op" => "test", "path" => "/name", "value" => "Alice"}, patch_index: 1, reason: {:test_failed, "Expected value '\\"Alice\\"' at '/name'"}}}
iex> # Patch will succeed, not applying invalid path operations.
iex> patch = [
...> %{op: "replace", path: "/name", value: "Alice"},
...> %{op: "replace", path: "/age", value: 42}
...> ]
iex> target = %{"name" => "Bob"} # No age in target
iex> Jsonpatch.apply_patch(patch, target, ignore_invalid_paths: true)
{:ok, %{"name" => "Alice"}}
"""
@spec apply_patch(t() | [t()], target :: Types.json_container(), Types.opts()) ::
{:ok, Types.json_container()} | {:error, Jsonpatch.Error.t()}
def apply_patch(json_patch, target, opts \\ []) do
# https://datatracker.ietf.org/doc/html/rfc6902#section-3
# > Operations are applied sequentially in the order they appear in the array.
{ignore_invalid_paths, opts} = Keyword.pop(opts, :ignore_invalid_paths, false)

json_patch
|> List.wrap()
|> Enum.with_index()
|> Enum.reduce_while({:ok, target}, fn {patch, patch_index}, {:ok, acc} ->
patch = cast_to_op_map(patch)

case do_apply_patch(patch, acc, opts) do
{:error, reason} ->
error = %Jsonpatch.Error{patch: patch, patch_index: patch_index, reason: reason}
{:halt, {:error, error}}
{:error, {error, _} = reason} ->
if ignore_invalid_paths && error == :invalid_path do

Check warning on line 78 in lib/jsonpatch.ex

View workflow job for this annotation

GitHub Actions / Analyze - OTP 25.2 / Elixir 1.13.4

Function body is nested too deep (max depth is 2, was 3).

Check warning on line 78 in lib/jsonpatch.ex

View workflow job for this annotation

GitHub Actions / Analyze - OTP 25.2 / Elixir 1.14.3

Function body is nested too deep (max depth is 2, was 3).
{:cont, {:ok, acc}}
else
error = %Jsonpatch.Error{patch: patch, patch_index: patch_index, reason: reason}
{:halt, {:error, error}}
end

{:ok, res} ->
{:cont, {:ok, res}}
Expand Down
2 changes: 1 addition & 1 deletion lib/jsonpatch/types.ex
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@ defmodule Jsonpatch.Types do
- `:atoms!` - path fragments are converted to existing atoms
- `{:custom, convert_fn}` - path fragments are converted with `convert_fn`
"""
@type opt_keys :: :strings | :atoms | {:custom, convert_fn()}
@type opt_keys :: :strings | :atoms | {:custom, convert_fn()} | {:ignore_invalid_paths, :boolean}

@typedoc """
Types options:
Expand Down
7 changes: 7 additions & 0 deletions test/jsonpatch_test.exs
Original file line number Diff line number Diff line change
Expand Up @@ -429,6 +429,13 @@ defmodule JsonpatchTest do
assert {:ok, ^expected} = Jsonpatch.apply_patch(patch, target)
end
end

test "ignore invalid paths when asked to" do
patch = %{"op" => "replace", "path" => "/inexistent", "value" => 42}
target = %{"foo" => "bar"}

assert {:ok, %{"foo" => "bar"}} = Jsonpatch.apply_patch(patch, target, ignore_invalid_paths: true)
end
end

defp string_to_existing_atom(data) when is_binary(data) do
Expand Down

0 comments on commit 2671eec

Please sign in to comment.