Compatible jsx encode/decode (#3230)

This commit is contained in:
JianBo He 2020-02-04 16:18:19 +08:00 committed by GitHub
parent 7ab3da399d
commit 3c459e8e74
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
4 changed files with 37 additions and 11 deletions

View File

@ -2,7 +2,7 @@
{deps, {deps,
[{gproc, "0.8.0"}, [{gproc, "0.8.0"},
{jiffy, "1.0.1"}, {jiffy, {git, "https://github.com/emqx/jiffy", {tag, "1.0.2"}}},
{cowboy, {git, "https://github.com/emqx/cowboy", {tag, "2.7.1"}}}, {cowboy, {git, "https://github.com/emqx/cowboy", {tag, "2.7.1"}}},
{esockd, {git, "https://github.com/emqx/esockd", {tag, "5.6.1"}}}, {esockd, {git, "https://github.com/emqx/esockd", {tag, "5.6.1"}}},
{ekka, {git, "https://github.com/emqx/ekka", {tag, "0.7.2"}}}, {ekka, {git, "https://github.com/emqx/ekka", {tag, "0.7.2"}}},

View File

@ -51,11 +51,11 @@
-spec(encode(json_term()) -> json_text()). -spec(encode(json_term()) -> json_text()).
encode(Term) -> encode(Term) ->
jiffy:encode(Term). encode(Term, []).
-spec(encode(json_term(), encode_options()) -> json_text()). -spec(encode(json_term(), encode_options()) -> json_text()).
encode(Term, Opts) -> encode(Term, Opts) ->
jiffy:encode(Term, Opts). jiffy:encode(to_ejson(Term), Opts).
-spec(safe_encode(json_term()) -spec(safe_encode(json_term())
-> {ok, json_text()} | {error, Reason :: term()}). -> {ok, json_text()} | {error, Reason :: term()}).
@ -77,7 +77,7 @@ decode(Json) -> decode(Json, []).
-spec(decode(json_text(), decode_options()) -> json_term()). -spec(decode(json_text(), decode_options()) -> json_term()).
decode(Json, Opts) -> decode(Json, Opts) ->
case jiffy:decode(Json, Opts) of {Term} -> Term; Other -> Other end. from_ejson(jiffy:decode(Json, Opts)).
-spec(safe_decode(json_text()) -spec(safe_decode(json_text())
-> {ok, json_term()} | {error, Reason :: term()}). -> {ok, json_term()} | {error, Reason :: term()}).
@ -94,3 +94,23 @@ safe_decode(Json, Opts) ->
{error, Reason} {error, Reason}
end. end.
%%--------------------------------------------------------------------
%% Helpers
%%--------------------------------------------------------------------
-compile({inline,
[ to_ejson/1
, from_ejson/1
]}).
to_ejson([{_, _}|_] = L) ->
lists:foldl(
fun({Name, Value}, Acc) ->
Acc#{Name => to_ejson(Value)}
end, #{}, L);
to_ejson(T) -> T.
from_ejson({L}) ->
[{Name, from_ejson(Value)} || {Name, Value} <- L];
from_ejson(T) -> T.

View File

@ -93,7 +93,7 @@ t_info(_) ->
{'$gen_call', From, info} -> {'$gen_call', From, info} ->
gen_server:reply(From, emqx_connection:info(st())) gen_server:reply(From, emqx_connection:info(st()))
after after
200 -> error("error") 100 -> error("error")
end end
end), end),
#{sockinfo := SockInfo} = emqx_connection:info(CPid), #{sockinfo := SockInfo} = emqx_connection:info(CPid),
@ -113,15 +113,15 @@ t_stats(_) ->
{'$gen_call', From, stats} -> {'$gen_call', From, stats} ->
gen_server:reply(From, emqx_connection:stats(st())) gen_server:reply(From, emqx_connection:stats(st()))
after after
0 -> error("error") 100 -> error("error")
end end
end), end),
Stats = emqx_connection:stats(CPid), Stats = emqx_connection:stats(CPid),
?assertMatch([{recv_oct,0}, ?assertMatch([{recv_oct,0},
{recv_cnt,0}, {recv_cnt,0},
{send_oct,0}, {send_oct,0},
{send_cnt,0}, {send_cnt,0},
{send_pend,0}| _] , Stats). {send_pend,0}| _] , Stats).
t_process_msg(_) -> t_process_msg(_) ->
with_conn(fun(CPid) -> with_conn(fun(CPid) ->
@ -384,7 +384,7 @@ trap_exit(Pid, Reason) ->
{'EXIT', Pid, Reason} -> ok; {'EXIT', Pid, Reason} -> ok;
{'EXIT', Pid, Other} -> error({unexpect_exit, Other}) {'EXIT', Pid, Other} -> error({unexpect_exit, Other})
after after
0 -> error({expect_exit, Reason}) 100 -> error({expect_exit, Reason})
end. end.
make_frame(Packet) -> make_frame(Packet) ->

View File

@ -45,6 +45,10 @@
%% {[{foo, bar}]} -> {"foo": "bar"} -> {[{<<"foo">>, <<"bar">>}]} %% {[{foo, bar}]} -> {"foo": "bar"} -> {[{<<"foo">>, <<"bar">>}]}
%% {[{<<"foo">>, <<"bar">>}]} -> {"foo": "bar"} -> {[{<<"foo">>, <<"bar">>}]} %% {[{<<"foo">>, <<"bar">>}]} -> {"foo": "bar"} -> {[{<<"foo">>, <<"bar">>}]}
%% #{<<"foo">> => <<"bar">>} -> {"foo": "bar"} -> #{<<"foo">> => <<"bar">>} %% #{<<"foo">> => <<"bar">>} -> {"foo": "bar"} -> #{<<"foo">> => <<"bar">>}
%%
%% Extension:
%% [{<<"foo">>, <<"bar">>}] -> {"foo": "bar"} -> [{<<"foo">>, <<"bar">>}]
%%
%%-------------------------------------------------------------------- %%--------------------------------------------------------------------
all() -> emqx_ct:all(?MODULE). all() -> emqx_ct:all(?MODULE).
@ -62,6 +66,7 @@ t_decode_encode(_) ->
[] = decode(encode({[]})), [] = decode(encode({[]})),
[{<<"foo">>, <<"bar">>}] = decode(encode({[{foo, bar}]})), [{<<"foo">>, <<"bar">>}] = decode(encode({[{foo, bar}]})),
[{<<"foo">>, <<"bar">>}] = decode(encode({[{<<"foo">>, <<"bar">>}]})), [{<<"foo">>, <<"bar">>}] = decode(encode({[{<<"foo">>, <<"bar">>}]})),
[{<<"foo">>, <<"bar">>}] = decode(encode([{<<"foo">>, <<"bar">>}])),
#{<<"foo">> := <<"bar">>} = decode(encode(#{<<"foo">> => <<"bar">>}), [return_maps]), #{<<"foo">> := <<"bar">>} = decode(encode(#{<<"foo">> => <<"bar">>}), [return_maps]),
JsonText = <<"{\"bool\":true,\"int\":10,\"foo\":\"bar\"}">>, JsonText = <<"{\"bool\":true,\"int\":10,\"foo\":\"bar\"}">>,
JsonMaps = #{<<"bool">> => true, JsonMaps = #{<<"bool">> => true,
@ -84,6 +89,7 @@ t_safe_decode_encode(_) ->
[] = safe_encode_decode({[]}), [] = safe_encode_decode({[]}),
[{<<"foo">>, <<"bar">>}] = safe_encode_decode({[{foo, bar}]}), [{<<"foo">>, <<"bar">>}] = safe_encode_decode({[{foo, bar}]}),
[{<<"foo">>, <<"bar">>}] = safe_encode_decode({[{<<"foo">>, <<"bar">>}]}), [{<<"foo">>, <<"bar">>}] = safe_encode_decode({[{<<"foo">>, <<"bar">>}]}),
[{<<"foo">>, <<"bar">>}] = safe_encode_decode([{<<"foo">>, <<"bar">>}]),
{ok, Json} = emqx_json:safe_encode(#{<<"foo">> => <<"bar">>}), {ok, Json} = emqx_json:safe_encode(#{<<"foo">> => <<"bar">>}),
{ok, #{<<"foo">> := <<"bar">>}} = emqx_json:safe_decode(Json, [return_maps]). {ok, #{<<"foo">> := <<"bar">>}} = emqx_json:safe_decode(Json, [return_maps]).