Skip to content

Commit

Permalink
Merge pull request #34 from nalundgaard/delete_nested
Browse files Browse the repository at this point in the history
Fix nested key deletion
  • Loading branch information
nalundgaard authored Feb 9, 2020
2 parents 7ee4206 + 20e3a86 commit 4b66ab4
Show file tree
Hide file tree
Showing 2 changed files with 37 additions and 11 deletions.
20 changes: 19 additions & 1 deletion src/jsn.erl
Original file line number Diff line number Diff line change
Expand Up @@ -753,7 +753,7 @@ empty_object(Options) ->
json_object() | json_array().
%%------------------------------------------------------------------------------
%% @private given a path as list of binary json_keys, a json_object, and a
%% value, upsate the object at the location defined by the path to the given
%% value, update the object at the location defined by the path to the given
%% to be value, and return the updated object
%%------------------------------------------------------------------------------
keys_set(Keys, Object, Value) when is_map(Object) ->
Expand Down Expand Up @@ -785,6 +785,8 @@ keys_set(Keys, {P}, Value, Empty) when is_list(P) ->
keys_set([Key | Rest], Object, Value, Empty)
when is_binary(Key), (is_list(Object) orelse is_map(Object)) ->
case key_get(Key, Object, jsn__undefined) of
E when Value =:= jsn__delete, (E =:= jsn__undefined orelse E =:= Empty) ->
return_if_object(Object, Empty);
E when E =:= jsn__undefined; E =:= Empty ->
key_set(Key, Object, keys_set(Rest, Empty, Value, Empty));
SubValue ->
Expand Down Expand Up @@ -852,6 +854,22 @@ set_nth(Index, _A, _V) ->
throw({error, {invalid_array_index, Index}}).


-spec return_if_object(MaybeObject :: json_object(),
Empty :: json_object()) -> json_object().
%%------------------------------------------------------------------------------
%% @private given a MaybeObject and the Empty object for the format,
%% return the object if it is one, or else throw a `not_an_object' error
%%------------------------------------------------------------------------------
return_if_object(M, _Empty) when is_map(M) ->
M;
return_if_object([{_,_}|_] = P, _Empty) ->
P;
return_if_object(Empty, Empty) ->
Empty;
return_if_object(Term, _Empty) ->
throw({error, {not_an_object, Term}}).


-spec keys_get(path_elements(),
json_term(),
Default :: term()) -> json_term() | term().
Expand Down
28 changes: 18 additions & 10 deletions test/jsn_tests.erl
Original file line number Diff line number Diff line change
Expand Up @@ -290,23 +290,31 @@ set_list_test_() ->
delete_test_() ->
Path1 = <<"foo.bar">>,
Path2 = <<"qux.lux">>,
Object1 = jsn:new([{Path1, <<"baz">>}, {Path2, [1,2,3]}]),
Path3 = <<"rox.sox">>,
Object1Plist = jsn:new([{Path1, <<"baz">>}, {Path2, [1,2,3]}], [{format, proplist}]),
Object1Map = jsn:new([{Path1, <<"baz">>}, {Path2, [1,2,3]}], [{format, map}]),
[?_assertEqual([], jsn:delete(<<"foo">>, [{<<"foo">>, <<"bar">>}])),
[?_assertEqual([], jsn:delete(Path3, [])),
?_assertEqual(#{}, jsn:delete(Path3, #{})),
?_assertEqual([], jsn:delete(<<"foo">>, [{<<"foo">>, <<"bar">>}])),
?_assertEqual(#{}, jsn:delete(<<"foo">>, #{<<"foo">> => <<"bar">>})),
?_assertEqual(jsn:new({Path2, [1,2,3]}), jsn:delete(foo, Object1)),
?_assertEqual(jsn:new({Path2, [1,2,3]}, [{format, map}]), jsn:delete(foo, Object1Map)),
?_assertEqual(jsn:new({Path1, <<"baz">>}), jsn:delete(qux, Object1)),
?_assertEqual(jsn:new({Path2, [1,2,3]}, [{format, proplist}]),
jsn:delete(foo, Object1Plist)),
?_assertEqual(jsn:new({Path2, [1,2,3]}, [{format, map}]),
jsn:delete(foo, Object1Map)),
?_assertEqual(jsn:new({Path1, <<"baz">>}, [{format, proplist}]),
jsn:delete(qux, Object1Plist)),
?_assertEqual(jsn:new({Path1, <<"baz">>}, [{format, map}]), jsn:delete(qux, Object1Map)),
?_assertEqual([2, 3], jsn:get(Path2, jsn:delete({<<"qux">>, <<"lux">>, first}, Object1))),
?_assertEqual(Object1Plist, jsn:delete(Path3, Object1Plist)),
?_assertEqual(Object1Map, jsn:delete(Path3, Object1Map)),
?_assertEqual([2, 3], jsn:get(Path2, jsn:delete({<<"qux">>, <<"lux">>, first}, Object1Plist))),
?_assertEqual([2, 3], jsn:get(Path2, jsn:delete({<<"qux">>, <<"lux">>, first}, Object1Map))),
?_assertEqual([2, 3], jsn:get(Path2, jsn:delete({<<"qux">>, <<"lux">>, 1}, Object1))),
?_assertEqual([2, 3], jsn:get(Path2, jsn:delete({<<"qux">>, <<"lux">>, 1}, Object1Plist))),
?_assertEqual([2, 3], jsn:get(Path2, jsn:delete({<<"qux">>, <<"lux">>, 1}, Object1Map))),
?_assertEqual([1, 3], jsn:get(Path2, jsn:delete({<<"qux">>, <<"lux">>, 2}, Object1))),
?_assertEqual([1, 3], jsn:get(Path2, jsn:delete({<<"qux">>, <<"lux">>, 2}, Object1Plist))),
?_assertEqual([1, 3], jsn:get(Path2, jsn:delete({<<"qux">>, <<"lux">>, 2}, Object1Map))),
?_assertEqual([1, 2], jsn:get(Path2, jsn:delete({<<"qux">>, <<"lux">>, 3}, Object1))),
?_assertEqual([1, 2], jsn:get(Path2, jsn:delete({<<"qux">>, <<"lux">>, 3}, Object1Plist))),
?_assertEqual([1, 2], jsn:get(Path2, jsn:delete({<<"qux">>, <<"lux">>, 3}, Object1Map))),
?_assertEqual([1, 2], jsn:get(Path2, jsn:delete({<<"qux">>, <<"lux">>, last}, Object1))),
?_assertEqual([1, 2], jsn:get(Path2, jsn:delete({<<"qux">>, <<"lux">>, last}, Object1Plist))),
?_assertEqual([1, 2], jsn:get(Path2, jsn:delete({<<"qux">>, <<"lux">>, last}, Object1Map))),
?_assertThrow({error, {not_an_object, _}}, jsn:delete(<<"k">>, [1,2,3])),
?_assertThrow({error, {not_an_object, _}}, jsn:delete(<<"k">>, <<"a">>)),
Expand Down

0 comments on commit 4b66ab4

Please sign in to comment.