Skip Menu |

This queue is for tickets about the JSON-Patch CPAN distribution.

Report information
The Basics
Id: 132954
Status: new
Priority: 0/
Queue: JSON-Patch

People
Owner: Nobody in particular
Requestors: jelices [...] hdi2.com
Cc:
AdminCc:

Bug Information
Severity: (no value)
Broken in: (no value)
Fixed in: (no value)



Subject: Possible bug in JSON::Patch
Date: Tue, 7 Jul 2020 13:46:45 +0200
To: bug-json-patch [...] rt.cpan.org
From: Javier Elices <jelices [...] hdi2.com>
Hello Michael,   First of all, a big thank you for all the useful libraries that you have available!   I have a web development that uses Perl for the batch work and Node and Javascript for the backend and frontend respectively. One of the Perl scripts uses your JSON::Patch library to compare a JSON that gets modified by the client App. This allows showing the changes diff-like to the admin as well as doing and undoing them. For all to work, the patches need to be correct and interoperable across Perl and Javascript. JSON Patch seems to be the way to go as that is exactly what promises...   Consider the following script: #!/usr/bin/env perl # JSON::Patch operations order bug? use strict; use warnings; use utf8; use JSON::XS; use JSON::Patch qw(diff patch); my $json1 = ' {   "one": [     { "a": [1, 2] },     { "b": [3, 4] },     { "c": [5, 6] }   ] } '; my $json2 = ' {   "one": [     { "a": [1, 2] }   ] } '; my $j1 = decode_json $json1; my $j2 = decode_json $json2; my $p2 = diff($j2, $j1); print JSON::XS->new->utf8->pretty->encode( $p2 ), "\n"; patch($j2, $p2);   The output of the script is (I am using version 0.04 of JSON::Patch): [    {       "path" : "/one/2",       "value" : {          "c" : [             5,             6          ]       },       "op" : "add"    },    {       "path" : "/one/1",       "value" : {          "b" : [             3,             4          ]       },       "op" : "add"    } ] Index is out of range, step #1 at /home/xxx/perl5/lib/perl5/Struct/Path.pm line 336.   I have seen that JSON::Patch::diff generates three types of operation based on the output of Struct::Diff::list_diff($diff, sort => 1). I think that "add" operations should be generated in the oposite order, while "remove" operations are being generated in the right order and "replace" operations could be generated in any order. That is assuming that Struct::Diff does not produce redundant differences.   I have checked the RFC 6902 specification to ensure and found (about "add" op's): o An element to add to an existing array - whereupon the supplied value is added to the array at the indicated location. Any elements at or above the specified index are shifted one position to the right. The specified index MUST NOT be greater than the number of elements in the array. If the "-" character is used to index the end of the array (see [RFC6901 <https://tools.ietf.org/html/rfc6901>]), this has the effect of appending the value to the array.   I have also tried a different JSON Patch library (Node this one, which I also use): https://json8.github.io/patch/demos/apply/ and it also does not like the order of the operations of the patch above.   I have thought about the problem and I think that a sorting step after the patch generation should be all it is required: * Group operations by type * Sort "add" operations in alphabetical path order * Sort "remove" operations in reverse alphabetical path order   I think this function takes care of it: sub patch_sort {   my $p = shift || [];   return [ sort {     ( $b->{op} cmp $a->{op} ) ||     (       $a->{op} eq 'remove'         ? $b->{path} cmp $a->{path}         : $a->{path} cmp $b->{path}     )   } @$p ]; }   It first sorts by "op", then for equal "op" it uses "path" in reverse alpha order for "remove" and in alpha order for the rest. This also sorts "replace" op's which I think does not harm.   In the above script, it will take this change: my $p2 = patch_sort( diff($j2, $j1) );   To get the patch in order. With that change it works.   I have tried more complex examples and the ordering seems to work. I share all this with you so you can think about the problem, see if you agree with me about the ordering and hopefully fix the library for other people to use. I have not studied your other libraries which JSON::Patch uses, so I may be missing something.   What do you think? Any feedback would be appreciated.   Thanks a lot for your time!   Best Regards,   Javier Elices.
Subject: Re: [rt.cpan.org #132954] AutoReply: Possible bug in JSON::Patch
Date: Wed, 8 Jul 2020 10:55:04 +0200
To: bug-JSON-Patch [...] rt.cpan.org
From: Javier Elices <jelices [...] hdi2.com>
  Actually, I think that it takes a little bit more to get the right order of the operations within a JSON Patch: sub patch_sort {   my $p = shift || [];   return [ sort {     ( $b->{op} cmp $a->{op} ) ||     (       $a->{op} eq 'remove'         ? path_cmp($b->{path}, $a->{path})         : path_cmp($a->{path}, $b->{path})     )   } @$p ]; } sub path_long {   my $p = shift || '';   return join( '/', map { $_ =~ /^\d+$/ ? sprintf("%09d", $_) : $_ } split('/', $p) ); } sub path_cmp {   my ($a, $b) = @_;   return path_long($a) cmp path_long($b); } El 07/07/2020 a las 14:09, Bugs in JSON-Patch via RT escribió: Show quoted text
> Greetings, > > This message has been automatically generated in response to the > creation of a trouble ticket regarding: > "Possible bug in JSON::Patch", > a summary of which appears below. > > There is no need to reply to this message right now. Your ticket has been > assigned an ID of [rt.cpan.org #132954]. Your ticket is accessible > on the web at: > > https://rt.cpan.org/Ticket/Display.html?id=132954 > > Please include the string: > > [rt.cpan.org #132954] > > in the subject line of all future correspondence about this issue. To do so, > you may reply to this message. > > Thank you, > bug-JSON-Patch@rt.cpan.org > > ------------------------------------------------------------------------- > Hello Michael, > >   First of all, a big thank you for all the useful libraries that you > have available! > >   I have a web development that uses Perl for the batch work and Node > and Javascript for the backend and frontend respectively. One of the > Perl scripts uses your JSON::Patch library to compare a JSON that gets > modified by the client App. This allows showing the changes diff-like to > the admin as well as doing and undoing them. For all to work, the > patches need to be correct and interoperable across Perl and Javascript. > JSON Patch seems to be the way to go as that is exactly what promises... > >   Consider the following script: > > #!/usr/bin/env perl > # JSON::Patch operations order bug? > > use strict; > use warnings; > use utf8; > > use JSON::XS; > use JSON::Patch qw(diff patch); > > my $json1 = ' > { >   "one": [ >     { "a": [1, 2] }, >     { "b": [3, 4] }, >     { "c": [5, 6] } >   ] > } > '; > > my $json2 = ' > { >   "one": [ >     { "a": [1, 2] } >   ] > } > '; > > my $j1 = decode_json $json1; > my $j2 = decode_json $json2; > > my $p2 = diff($j2, $j1); > print JSON::XS->new->utf8->pretty->encode( $p2 ), "\n"; > patch($j2, $p2); > >   The output of the script is (I am using version 0.04 of JSON::Patch): > > [ >    { >       "path" : "/one/2", >       "value" : { >          "c" : [ >             5, >             6 >          ] >       }, >       "op" : "add" >    }, >    { >       "path" : "/one/1", >       "value" : { >          "b" : [ >             3, >             4 >          ] >       }, >       "op" : "add" >    } > ] > > Index is out of range, step #1 at > /home/xxx/perl5/lib/perl5/Struct/Path.pm line 336. > >   I have seen that JSON::Patch::diff generates three types of operation > based on the output of Struct::Diff::list_diff($diff, sort => 1). I > think that "add" operations should be generated in the oposite order, > while "remove" operations are being generated in the right order and > "replace" operations could be generated in any order. That is assuming > that Struct::Diff does not produce redundant differences. > >   I have checked the RFC 6902 specification to ensure and found (about > "add" op's): > > o An element to add to an existing array - whereupon the supplied > value is added to the array at the indicated location. Any > elements at or above the specified index are shifted one position > to the right. The specified index MUST NOT be greater than the > number of elements in the array. If the "-" character is used to > index the end of the array (see [RFC6901 <https://tools.ietf.org/html/rfc6901>]), this has the effect of > appending the value to the array. > > >   I have also tried a different JSON Patch library (Node this one, > which I also use): https://json8.github.io/patch/demos/apply/ and it > also does not like the order of the operations of the patch above. > >   I have thought about the problem and I think that a sorting step > after the patch generation should be all it is required: > > * Group operations by type > * Sort "add" operations in alphabetical path order > * Sort "remove" operations in reverse alphabetical path order > >   I think this function takes care of it: > > sub patch_sort { >   my $p = shift || []; > >   return [ sort { >     ( $b->{op} cmp $a->{op} ) || >     ( >       $a->{op} eq 'remove' >         ? $b->{path} cmp $a->{path} >         : $a->{path} cmp $b->{path} >     ) >   } @$p ]; > } > >   It first sorts by "op", then for equal "op" it uses "path" in reverse > alpha order for "remove" and in alpha order for the rest. This also > sorts "replace" op's which I think does not harm. > >   In the above script, it will take this change: > > my $p2 = patch_sort( diff($j2, $j1) ); > >   To get the patch in order. With that change it works. > >   I have tried more complex examples and the ordering seems to work. I > share all this with you so you can think about the problem, see if you > agree with me about the ordering and hopefully fix the library for other > people to use. I have not studied your other libraries which JSON::Patch > uses, so I may be missing something. > >   What do you think? Any feedback would be appreciated. > >   Thanks a lot for your time! > >   Best Regards, > >   Javier Elices. > >