Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Some fixes #14

Open
wants to merge 7 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion include/json_rec_types.hrl
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@

-type proplist() :: list({term(),term()}).

-type json_dict() :: {struct, proplist()}.
-type json_dict() :: {struct, proplist()} | {proplist()}.
-type json() :: json_dict()|list(term()).


Expand Down
2 changes: 1 addition & 1 deletion rebar.config
Original file line number Diff line number Diff line change
Expand Up @@ -3,4 +3,4 @@
{parse_trans, "", {git, "https://github.com/uwiger/parse_trans.git", {branch, "master"}}}
]}.
{erl_opts, [debug_info]}.

{lib_dirs, ["deps"]}.
147 changes: 97 additions & 50 deletions src/json_rec.erl
Original file line number Diff line number Diff line change
Expand Up @@ -31,75 +31,88 @@

-export([
to_rec/3,
to_json/2
to_json/2,
to_json/3
]).

-include("json_rec_types.hrl").
-include("../include/json_rec_types.hrl").


%% note: I am using tuple() for record, since this is a generic record
-spec to_json(Record :: tuple(), Module :: [atom()]) -> {struct, proplist()};
(Record :: tuple(), Module :: atom()) -> {struct, proplist()}.

to_json(Record, Module) when is_list(Module) ->
Fields = module_rec_fields(Module,Record),
Pl = rec_keys(Fields, Record, Module, []),
{struct, Pl};

to_json(Record, Module) ->
Fields = module_rec_fields([Module],Record),
Pl = rec_keys(Fields,Record,[Module],[]),
{struct, Pl}.
to_json(Record, Module, mochi).

-spec to_json(Record :: tuple(), Module :: [atom()], mochi) -> {struct, proplist()};
(Record :: tuple(), Module :: atom(), mochi) -> {struct, proplist()};
(Record :: tuple(), Module :: atom(), eep) -> {proplist()};
(Record :: tuple(), Module :: [atom()], eep) -> {proplist()}.
to_json(Record, Module, ConvType) when is_list(Module) ->
Fields = module_rec_fields(Module,Record),
Pl = rec_keys(Fields, Record, Module, ConvType, []),
pl_to_json(Pl, ConvType);
to_json(Record, Module, ConvType) ->
Fields = module_rec_fields([Module],Record),
Pl = rec_keys(Fields,Record,[Module],ConvType, []),
pl_to_json(Pl, ConvType).

rec_keys([], _Record, _Module, Acc) -> Acc;
rec_keys([Field|Rest],Record,Module,Acc) ->
Value = module_get(Module, Field, Record),
Key = list_to_binary(atom_to_list(Field)),
JsonValue = field_value(Value,Module,[]),
rec_keys(Rest, Record, Module,[{Key,JsonValue}|Acc]).
rec_keys([], _Record, _Module, _ConvType, Acc) -> Acc;
rec_keys([Field|Rest],Record,Module, ConvType, Acc) ->
case module_get(Module, Field, Record) of
undefined ->
rec_keys(Rest, Record, Module, ConvType, Acc);
Value ->
Key = list_to_binary(atom_to_list(Field)),
JsonValue = field_value(Value,Module, ConvType, []),
rec_keys(Rest, Record, Module, ConvType, [{Key,JsonValue}|Acc])
end.

field_value(Value, Module, _Acc) when is_tuple(Value) ->
field_value(Value, Module, ConvType, _Acc) when is_tuple(Value) ->
case module_has_rec(Module, Value, false) of
false ->
Value;
_M when is_atom(_M) ->
to_json(Value,Module)
to_json(Value,Module,ConvType)
end;
field_value(Value, _Module, _Acc) when Value =:= null;
Value =:= false;
Value =:= true ->
field_value(Value, _Module, _ConvType, _Acc) when Value =:= null;
Value =:= false;
Value =:= true ->
Value;
field_value(Value, _Module, _Acc) when is_atom(Value) ->
field_value(Value, _Module, _ConvType, _Acc) when is_atom(Value) ->
list_to_binary(atom_to_list(Value));

field_value([],_Module, Acc) -> lists:reverse(Acc);
field_value([{_,_}|_] = Pl, Module, Acc) ->
field_value([],_Module, _ConvType, Acc) -> lists:reverse(Acc);
field_value([{_,_}|_] = Pl, Module, ConvType, Acc) ->
%% it is a proplist, make it a dict
{struct, [{Key, Value} || {Key, V2} <- Pl,
pl_to_json([{Key, Value} || {Key, V2} <- Pl,
begin
Value = field_value(V2, Module, Acc),
Value = field_value(V2, Module, ConvType, Acc),
true
end]};
end], ConvType);

field_value([Value|Rest], Module, Acc) ->
NewValue = case field_value(Value,Module,[]) of
field_value([Value|Rest], Module, ConvType, Acc) ->
NewValue = case field_value(Value,Module,ConvType,[]) of
IsRec when is_tuple(IsRec),
is_atom(element(1,Value)) ->
%% this returned a record, so get the first
%% element from the rec tuple and do: {struct,
%% atom
{struct, [{list_to_binary(atom_to_list(element(1,Value))),IsRec}]};
pl_to_json([{list_to_binary(atom_to_list(element(1,Value))),IsRec}], ConvType);
%% IsTuple when is_tuple(IsTuple) ->
%% tuple_to_list(IsTuple);
NotRec ->
NotRec
end,
field_value(Rest, Module,[NewValue|Acc]);
field_value(Value,_Module,_Acc) ->
field_value(Rest, Module, ConvType, [NewValue|Acc]);
field_value(Value,_Module,_ConvType,_Acc) ->
Value.


pl_to_json(KV, mochi) ->
{struct, KV};
pl_to_json(KV, _) ->
{KV}.


%% @spec to_rec(_Json, Module, Record) -> tuple()
Expand All @@ -119,55 +132,84 @@ field_value(Value,_Module,_Acc) ->

to_rec({struct, Pl} = _Json, Module, undefined) when is_list(Module) ->
pl(Pl, Module);
to_rec({Pl} = _Json, Module, undefined) when is_list(Module) ->
pl(Pl, Module);
to_rec({struct, Pl} = _Json, Module, undefined) ->
pl(Pl, [Module]);
to_rec({Pl} = _Json, Module, undefined) ->
pl(Pl, [Module]);

to_rec({struct, Pl} = _Json, Module, Rec) when is_list(Module) ->
keys_rec(Pl, Module, Rec);
to_rec({Pl} = _Json, Module, Rec) when is_list(Module) ->
keys_rec(Pl, Module, Rec);
to_rec({struct, Pl} = _Json, Module, Rec) ->
keys_rec(Pl, [Module], Rec);
to_rec({Pl} = _Json, Module, Rec) ->
keys_rec(Pl, [Module], Rec).

keys_rec([], _Module, Rec) -> Rec;
keys_rec([{Key, {struct, Pl}}|Rest], Module, Rec) ->
Field = list_to_atom(binary_to_list(Key)),
Value = case module_new(Module, Key, undefined) of
UpRec = keys_rec_subrec(Key, Module, Pl, Rec),
keys_rec(Rest, Module, UpRec);
keys_rec([{Key, {Pl}}|Rest], Module, Rec) ->
UpRec = keys_rec_subrec(Key, Module, Pl, Rec),
keys_rec(Rest, Module, UpRec);
keys_rec([{Key, Value}|Rest], Module, Rec) ->
Field = binary_to_atom(Key, utf8),
NewValue = to_value(Value,Module),
NewRec = module_set(Module, {Field, NewValue}, Rec),
keys_rec(Rest,Module,NewRec).

keys_rec_subrec(Key, Module, Pl, Rec) ->
Field = binary_to_atom(Key, utf8),
RecName = atom_to_binary(element(1, Rec), utf8),
Value = case module_new(Module, {RecName, Key}, undefined) of
undefined ->
%% this is not a sub record, so just pl it
pl(Pl,Module);
case module_new(Module, Key, undefined) of
undefined ->
pl(Pl,Module);
SubRec ->
%% we have a new record, go back go the topproplist
to_rec({struct,Pl}, Module, SubRec)
end;
SubRec ->
%% we have a new record, go back go the topproplist
to_rec({struct,Pl}, Module, SubRec)
end,
UpRec = module_set(Module, {Field,Value}, Rec),
keys_rec(Rest, Module, UpRec);

keys_rec([{Key, Value}|Rest], Module, Rec) ->
Field = list_to_atom(binary_to_list(Key)),
NewValue = to_value(Value,Module),
NewRec = module_set(Module, {Field, NewValue}, Rec),
keys_rec(Rest,Module,NewRec).
UpRec.

pl(P, Module) ->
pl(P,Module,[]).
pl([],_M,[H]) -> H;
pl([],_M,Acc) -> lists:reverse(Acc);
pl([{Key, {struct,Pl}}|Rest], Module, Acc) ->
Value = pl_subrec_value(Pl, Key, Module),
pl(Rest, Module, [Value|Acc]);
pl([{Key, {Pl}}|Rest], Module, Acc) ->
Value = pl_subrec_value(Pl, Key, Module),
pl(Rest, Module, [Value|Acc]);
pl([{Key,Value}|Rest], Module, Acc) ->
pl(Rest, Module, [{Key,Value}|Acc]).

pl_subrec_value(Pl, Key, Module) ->
Value = case module_new(Module,Key,undefined) of
undefined ->
{Key, pl(Pl, Module, [])};
Rec ->
to_rec({struct, Pl}, Module, Rec)
end,
pl(Rest, Module, [Value|Acc]);
pl([{Key,Value}|Rest], Module, Acc) ->
pl(Rest, Module, [{Key,Value}|Acc]).
Value.

to_value(V, Module) ->
to_value(V, Module, []).

to_value({struct, Pl}, Module, _Acc) ->
pl(Pl,Module);
to_value([], _Module, Acc) -> Acc;
to_value({Pl}, Module, _Acc) ->
pl(Pl,Module);
to_value([], _Module, Acc) -> lists:reverse(Acc);
to_value([H|T],Module, Acc) ->
to_value(T,Module,[to_value(H,Module,[])|Acc]);
to_value(V,_Module,_Acc) -> V.
Expand Down Expand Up @@ -200,9 +242,14 @@ module_has_rec([M|T],Rec, Act) ->



module_set(Ms, Kv, Rec) ->
module_set(Ms, Kv={K,_}, Rec) ->
M = module_has_rec(Ms,Rec),
M:'#set-'([Kv],Rec).
case M:'#pos-'(element(1, Rec), K) of
0 ->
Rec;
_ ->
M:'#set-'([Kv],Rec)
end.

module_rec_fields(Ms, Rec ) ->
M = module_has_rec(Ms,Rec),
Expand Down