Browse Source

Add `skip_undefined` option

Takeru Ohta 4 years ago
parent
commit
86780e1872
3 changed files with 21 additions and 3 deletions
  1. 4 0
      src/jsone.erl
  2. 11 3
      src/jsone_encode.erl
  3. 6 0
      test/jsone_encode_tests.erl

+ 4 - 0
src/jsone.erl

@@ -197,6 +197,7 @@
                        | {space, non_neg_integer()}
                        | {indent, non_neg_integer()}
                        | {map_unknown_value, fun ((term()) -> {ok, json_value()} | error)}
+                       | skip_undefined
                        | common_option().
 %% `native_utf8': <br />
 %% - Encodes non ASCII UTF-8 characters as a human-readable(non-escaped) string <br />
@@ -231,6 +232,9 @@
 %% - Inserts a newline and `N' spaces for each level of indentation <br />
 %% - default: `0' <br />
 %%
+%% `skip_undefined': <br />
+%% - If speficied, each entry having `undefined' value in a object isn't included in the result JSON <br />
+%%
 %% `{map_unknown_value, Fun}`: <br />
 %% - If specified, unknown values encountered during an encoding process are converted to `json_value()` by applying `Fun'.
 

+ 11 - 3
src/jsone_encode.erl

@@ -71,6 +71,7 @@
           space = 0 :: non_neg_integer(),
           indent = 0 :: non_neg_integer(),
           undefined_as_null = false :: boolean(),
+          skip_undefined = false :: boolean(),
           map_unknown_value = undefined :: undefined | fun ((term()) -> {ok, jsone:json_value()} | error)
          }).
 -define(OPT, #encode_opt_v2).
@@ -330,9 +331,14 @@ object(Members, Nexts, Buf, Opt) ->
     object_members(Members, Nexts, pp_newline(<<Buf/binary, ${>>, Nexts, 1, Opt), Opt).
 
 -spec object_members(jsone:json_object_members(), [next()], binary(), opt()) -> encode_result().
-object_members([],                  Nexts, Buf, Opt) -> next(Nexts, <<(pp_newline(Buf, Nexts, Opt))/binary, $}>>, Opt);
-object_members([{Key, Value} | Xs], Nexts, Buf, Opt) -> object_key(Key, [{object_value, Value, Xs} | Nexts], Buf, Opt);
-object_members(Arg, Nexts, Buf, Opt)                 -> ?ERROR(object_members, [Arg, Nexts, Buf, Opt]).
+object_members([], Nexts, Buf, Opt) ->
+    next(Nexts, <<(pp_newline(Buf, Nexts, Opt))/binary, $}>>, Opt);
+object_members([{_, undefined} | Xs], Nexts, Buf, ?OPT{skip_undefined=true}=Opt) ->
+    object_members(Xs, Nexts, Buf, Opt);
+object_members([{Key, Value} | Xs], Nexts, Buf, Opt) ->
+    object_key(Key, [{object_value, Value, Xs} | Nexts], Buf, Opt);
+object_members(Arg, Nexts, Buf, Opt) ->
+    ?ERROR(object_members, [Arg, Nexts, Buf, Opt]).
 
 -spec object_value(jsone:json_value(), jsone:json_object_members(), [next()], binary(), opt()) -> encode_result().
 object_value(Value, Members, Nexts, Buf, Opt) ->
@@ -394,6 +400,8 @@ parse_option([{datetime_format, Fmt}|T], Opt) ->
     end;
 parse_option([undefined_as_null|T],Opt) ->
     parse_option(T, Opt?OPT{undefined_as_null = true});
+parse_option([skip_undefined|T],Opt) ->
+    parse_option(T, Opt?OPT{skip_undefined = true});
 parse_option([{map_unknown_value, F}|T], Opt) when is_function(F, 1) ->
     parse_option(T, Opt?OPT{map_unknown_value = F});
 parse_option(List, Opt) ->

+ 6 - 0
test/jsone_encode_tests.erl

@@ -262,6 +262,12 @@ encode_test_() ->
               ?assertEqual({ok,<<"null">>},          jsone_encode:encode(undefined,[undefined_as_null])), % OK
               ?assertEqual({ok,<<"\"undefined\"">>}, jsone_encode:encode(undefined,[])) % OK
       end},
+     {"skip_undefined option",
+      fun() ->
+              Object = #{<<"1">> => undefined, <<"2">> => 3},
+              ?assertEqual({ok,<<"{\"1\":null,\"2\":3}">>}, jsone_encode:encode(Object,[undefined_as_null])),
+              ?assertEqual({ok,<<"{\"2\":3}">>},            jsone_encode:encode(Object,[skip_undefined]))
+      end},
 
      %% Pretty Print
      {"space",