Skip to content
This repository has been archived by the owner on Jan 12, 2023. It is now read-only.

Commit

Permalink
Nested record support added
Browse files Browse the repository at this point in the history
  • Loading branch information
Richard Jonas committed Jul 7, 2015
1 parent 84a5694 commit 7cd80e5
Show file tree
Hide file tree
Showing 6 changed files with 56 additions and 10 deletions.
30 changes: 28 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -76,6 +76,32 @@ to_json({person, "John Doe", male, 43, <<"43231-fec112">>}).

Note that ejson puts type information into JSON results, so when we pass those JSONs back, ejson will know what type it needs to convert from those JSONs. Sometimes it is not possible to put those `__rec` fields into the JSON, in that case we need to specify the target type in the rule definition.

#### Nested records

Obviously not just numeric and boolean values can be in a record but records itselfes. If a field value is a tuple, it will be treated as a record.

```erlang
-json({book, {string, "title"}, "author", "year"}).
-json({author, {string, "firstName"},
{string, "midName", [{default, ""}]},
{string, "lastName"}}).
```

In the author field you can put an author record value, the converted will convert in as a nested JSON as you expect.

```json
{
"__rec": "book",
"title": "How to get things done in 24 hours for dummies",
"author":
{
"firstName": "John",
"lastName": "Smith"
},
"year": 2014
}
```

#### Lists to arrays

In Erlang lists are strings basically, so if we want to convert list of values we need to specify that (tell ejson that it is not a string).
Expand Down Expand Up @@ -207,7 +233,7 @@ The result is
}
```
Another example using `field\_fun` to convert times.
Another example using `field_fun` to convert times.
```erlang
-json({event, id, {field_fun, time, {?MODULE, to_jstime},
Expand Down Expand Up @@ -253,7 +279,7 @@ handle_req(Id) ->

### Caching module attributes

Sometimes you don't want to collect the module attributes and filter the json wild attributes for one thousand elements one by one. So there is a possibility to collect them manually and pass them to `to\_json/2` function.
Sometimes you don't want to collect the module attributes and filter the json wild attributes for one thousand elements one by one. So there is a possibility to collect them manually and pass them to `to_json/2` function.
```erlang
convert_list(List) ->
Expand Down
2 changes: 1 addition & 1 deletion rebar.config
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@

{deps, [
{jsx, ".*",
{git, "git://github.com/talentdeficit/jsx.git", {tag, "v1.4.4"}}},
{git, "git://github.com/talentdeficit/jsx.git", {tag, "v2.6.2"}}},
{proper, ".*",
{git, "git://github.com/manopapad/proper.git"}},
{eper, ".*",
Expand Down
5 changes: 4 additions & 1 deletion src/ejson.erl
Original file line number Diff line number Diff line change
Expand Up @@ -51,7 +51,10 @@
%%% External API functions
%%%============================================================================

-spec to_json_modules(term(), [module()]) -> binary().
-spec to_json_modules(term(), [module()]) ->
{ok, binary()} |
{error, {duplicate_records, term()}} |
{error, {duplicate_fields, term()}}.
to_json_modules(Term, ModuleList) ->
Opts = json_props(ModuleList),
to_json(Term, Opts).
Expand Down
6 changes: 3 additions & 3 deletions src/ejson_decode.erl
Original file line number Diff line number Diff line change
Expand Up @@ -132,7 +132,7 @@ extract_value(Rule, Value, Opts) ->
{const, _, _} ->
undefined;
_AttrName when is_list(Value) ->
decode(Value, Opts);
decode1(Value, Opts);
_AttrName ->
%% number and boolean case
Value
Expand Down Expand Up @@ -167,11 +167,11 @@ extract_list(Value, FieldOpts, Opts) ->
[decode1(V, Opts, Type) || V <- Value]
end.

extract_field_fun(Value, {M, F}, Value, Opts) ->
extract_field_fun(Value, {M, F}, Value, _Opts) ->
try erlang:apply(M, F, [Value]) of
Val ->
Val
%%decode(Val, Opts)
%%decode1(Val, Opts)
catch
E:R ->
{error, {field_run, {M, F}, {E, R}}}
Expand Down
4 changes: 2 additions & 2 deletions src/ejson_encode.erl
Original file line number Diff line number Diff line change
Expand Up @@ -64,7 +64,7 @@ encode1(Tuple, Opts) when is_tuple(Tuple) andalso is_atom(element(1, Tuple)) ->
Error;
Fields ->
%% Convert each values
Meta = [{<<"__rec">>, ?BIN(RecordName)}],
Meta = [{<<"__rec">>, atom_to_binary(RecordName, utf8)}],
case convert(ejson_util:zip(Fields, Values), Tuple, Opts, Meta) of
{error, _} = Error ->
Error;
Expand Down Expand Up @@ -145,7 +145,7 @@ apply_rule(Name, Tuple, Value, Opts) ->
atom_rule(AttrName, undefined) ->
{AttrName, null};
atom_rule(AttrName, Value) when is_atom(Value) ->
{AttrName, ?BIN(Value)};
{AttrName, atom_to_binary(Value, utf8)};
atom_rule(AttrName, Value) ->
{error, {atom_value_expected, AttrName, Value}}.

Expand Down
19 changes: 18 additions & 1 deletion test/ejson_trans_test.erl
Original file line number Diff line number Diff line change
Expand Up @@ -6,8 +6,25 @@

-json({square, "side"}).

all_test_() ->
-json({book, {string, "title"}, "author", "year"}).
-json({author, {string, "firstName"},
{string, "midName", [{default, ""}]},
{string, "lastName"}}).

simple_test_() ->
Record = {square, 50},
{ok, Json} = to_json(Record),
{ok, Square} = from_json(Json),
?_assert(Record =:= Square).

book_test_() ->
A1 = {author, "John", undefined, "Smith"},
A2 = {author, "John", "Davison", "Rockefeller"},
B1 = {book, "The theory of markets", A2, 1933},
B2 = {book, "How to get things done in 24 hours", A1, 2014},
{ok, J1} = to_json(B1),
{ok, J2} = to_json(B2),
{ok, D1} = from_json(J1),
{ok, D2} = from_json(J2),
[?_assertEqual(D1, B1),
?_assertEqual(D2, B2)].

0 comments on commit 7cd80e5

Please sign in to comment.