Browse Source

Allow configuring a json module for encode/decode for the json codec

Uman Shahzad 5 years ago
parent
commit
703f067a95
1 changed files with 32 additions and 3 deletions
  1. 32 3
      src/datatypes/epgsql_codec_json.erl

+ 32 - 3
src/datatypes/epgsql_codec_json.erl

@@ -17,18 +17,47 @@
 
 
 -define(JSONB_VERSION_1, 1).
 -define(JSONB_VERSION_1, 1).
 
 
-%% TODO: JSON encode/decode `fun Mod:Name/1` / `{Mod, Name}` as option.
-%% Shall not pass `fun(_) -> .. end`, because of hot code upgrade problems.
-init(_, _) -> [].
+%% JsonMod shall either be a module with encode/1 and decode/1, where:
+%%
+%% - encode/1 expects erlang-formatted JSON, e.g. a map or a proplist,
+%%   and returns a valid JSON binary string.
+%% - decode/1 expects a valid JSON binary string, and returns erlang-formatted JSON.
+%%
+%% or a tuple {Mod, {encode, Opts}, {decode, Opts}} where Mod implements encode/2 and
+%% decode/2 with the same interface semantics as encode/1 and decode/1, while
+%% accepting Opts as options to pass into the encode/2 and decode/2 functions.
+%%
+%% Tip: if you require special behavior that a third-party JSON module doesn't provide
+%%      for you, or which doesn't strictly meet this interface requirement, wrap the
+%%      third-party JSON module in a new module that implements the required interface,
+%%      and pass in _that_ as JsonMod.
+init(JsonMod, _) ->
+    JsonMod.
 
 
 names() ->
 names() ->
     [json, jsonb].
     [json, jsonb].
 
 
+encode(ErlJson, json, JsonMod) when is_atom(JsonMod) ->
+    JsonMod:encode(ErlJson);
+encode(ErlJson, json, {JsonMod, {encode, Opts}, _}) when is_atom(JsonMod) ->
+    JsonMod:encode(ErlJson, Opts);
+encode(ErlJson, jsonb, JsonMod) when is_atom(JsonMod) ->
+    <<?JSONB_VERSION_1:8, (JsonMod:encode(ErlJson))/binary>>;
+encode(ErlJson, jsonb, {JsonMod, {encode, Opts}, _}) when is_atom(JsonMod) ->
+    <<?JSONB_VERSION_1:8, (JsonMod:encode(ErlJson, Opts))/binary>>;
 encode(Bin, json, _) ->
 encode(Bin, json, _) ->
     Bin;
     Bin;
 encode(Bin, jsonb, _) ->
 encode(Bin, jsonb, _) ->
     [<<?JSONB_VERSION_1:8>> | Bin].
     [<<?JSONB_VERSION_1:8>> | Bin].
 
 
+decode(Bin, json, JsonMod) when is_atom(JsonMod) ->
+    JsonMod:decode(Bin);
+decode(Bin, json, {JsonMod, _, {decode, Opts}}) when is_atom(JsonMod) ->
+    JsonMod:decode(Bin, Opts);
+decode(<<?JSONB_VERSION_1:8, Bin/binary>>, jsonb, JsonMod) when is_atom(JsonMod) ->
+    JsonMod:decode(Bin);
+decode(<<?JSONB_VERSION_1:8, Bin/binary>>, jsonb, {JsonMod, _, {decode, Opts}}) when is_atom(JsonMod) ->
+    JsonMod:decode(Bin, Opts);
 decode(Bin, json, _) ->
 decode(Bin, json, _) ->
     Bin;
     Bin;
 decode(<<?JSONB_VERSION_1:8, Bin/binary>>, jsonb, _) ->
 decode(<<?JSONB_VERSION_1:8, Bin/binary>>, jsonb, _) ->