corka149 / jsonpatch

A implementation of RFC 6902 in pure Elixir.

Geek Repo:Geek Repo

Github PK Tool:Github PK Tool

Something wrong in handling list

smartepsh opened this issue · comments

Describe the bug

  1. The array is a legal json structured type, but can't apply a patch for a list directly. (Maybe it's your feature...)
  2. Can't handle list well. (see examples below)
  3. (Suggestion) Swap arguments of Jsonpatch.apply_patch/2 so that the pipeline can be used. map |> Jsonpatch.apply_patch!(diff_1) |> Jsonpatch.apply_patch!(diff_2)

To Reproduce

Example 1:

  base = %{list: [1, 2, 3]}
  target = %{list: [2, 3, 1]}
  diff = Jsonpatch.diff(base, target)
  Jsonpatch.apply_patch!(diff, base)

Example 2:

  base = %{list: [%{a: 1}, %{b: 2}, %{c: 3}]}
  target = %{list: [%{b: 2}, %{c: 3}, %{a: 1}]}
  diff = Jsonpatch.diff(base, target)
  Jsonpatch.apply_patch!(diff, base)

Expected behavior

I hope the result of Jsonpatch.after_patch!(diff, base) is equal to target .

Screenshots

Example 1:

image

Example 2:

image

Desktop (please complete the following information):

  • Elixir - 1.13.3
  • Erlang - 24.2.1
  • System - MacOS 12.3.1

Thanks for the report!

(Maybe it's your feature...)

Indeed. This is my fault that there is no hint in the documentation, yet. The issue is the map and not the list because it is atom based map. Atoms as keys are not supported, yet.

Why? So far, I saw only JSON parser that create maps with strings as keys because they are safer in case not trusted JSON is parsed. Else it would be possible to trigger the creation of atoms from the outside (when we are talking about REST interfaces for example). I followed this philosophy but never stated it anywhere.
(The path of the patch operation must be converted into an atom.)

But today I think it should be possible to use something like an option. Example:

Jsonpatch.apply_patch!(diff, base, allow_atoms: true)

In addition the error message could be more useful.

  • Improve error message in case of maps with atom keys
  • Mention danger of using maps with atom keys
  • Add option to allow the creation of atoms

I have no spare time this week. If its urgent or you are interest in solving it - feel free to create a PR. 🙏

Thanks for the reply.

I hadn't noticed before that this was a problem with atom keys 😮‍💨 I have another example about the list with the string key's map.

Example 3

  base = %{"key" => []}
  target = %{"key" => [1, 2, 3]}
  diff = Jsonpatch.diff(base, target)
  Jsonpatch.apply_patch!(diff, base)

image

It restores only one element of the list. I think it's about the diff order.

You are right. Jsonpatch.apply_patch should follow the order.

On the other hand, the result of the diff should be in the same orders as they are detected. That should be changed.

  • Produce diff in the same order as they are detected

You are right. Jsonpatch.apply_patch should follow the order.

On the other hand, the result of the diff should be in the same orders as they are detected. That should be changed.

  • Produce diff in the same order as they are detected

This is more important to us, so I took care of that first. Please. #9

Nice - thanks for the contribution! I merged it and published version 0.12.1. :-)

The progress looks good so far:

iex(1)> base = %{list: [1, 2, 3]}
%{list: [1, 2, 3]}
iex(2)> target = %{list: [2, 3, 1]}
%{list: [2, 3, 1]}
iex(3)> diff = Jsonpatch.diff(base, target)
[
  %Jsonpatch.Operation.Replace{path: "/list/0", value: 2},
  %Jsonpatch.Operation.Replace{path: "/list/1", value: 3},
  %Jsonpatch.Operation.Replace{path: "/list/2", value: 1}
]
iex(4)> Jsonpatch.apply_patch!(diff, base, keys: :atoms)
%{list: [2, 3, 1]}

I think only tests are missing.

The change is now in main and released under version 0.13.0.