Browse Source

Add `codecs` connect option

Сергей Прохоров 7 years ago
parent
commit
58bd3635ea
4 changed files with 37 additions and 23 deletions
  1. 2 1
      README.md
  2. 17 6
      src/epgsql.erl
  3. 16 14
      src/epgsqla.erl
  4. 2 2
      src/epgsqli.erl

+ 2 - 1
README.md

@@ -69,6 +69,7 @@ see `CHANGES` for full list.
     {ssl_opts, SslOptions :: [ssl:ssl_option()]}   | % @see OTP ssl app, ssl_api.hrl
     {timeout,  TimeoutMs  :: timeout()}            | % default: 5000 ms
     {async,    Receiver   :: pid() | atom()}       | % process to receive LISTEN/NOTIFY msgs
+    {codecs,   Codecs     :: [{epgsql_codec:codec_mod(), any()}]} |
     {replication, Replication :: string()}. % Pass "database" to connect in replication mode
     
 -spec connect(host(), string(), string(), [connect_option()] | map())
@@ -78,7 +79,7 @@ see `CHANGES` for full list.
 %% `Host'     - host to connect to
 %% `Username' - username to connect as, defaults to `$USER'
 %% `Password' - optional password to authenticate with
-%% `Opts'     - proplist of extra options
+%% `Opts'     - proplist or map of extra options
 %% returns `{ok, Connection}' otherwise `{error, Reason}'
 connect(Host, Username, Password, Opts) -> ...
 ```

+ 17 - 6
src/epgsql.erl

@@ -53,6 +53,7 @@
     {ssl_opts, SslOptions :: [ssl:ssl_option()]}   | % see OTP ssl app, ssl_api.hrl
     {timeout,  TimeoutMs  :: timeout()}            | % default: 5000 ms
     {async,    Receiver   :: pid() | atom()}       | % process to receive LISTEN/NOTIFY msgs
+    {codecs,   Codecs     :: [{epgsql_codec:codec_mod(), any()}]} |
     {replication, Replication :: string()}. % Pass "database" to connect in replication mode
 
 -ifdef(have_maps).
@@ -67,6 +68,7 @@
           ssl_opts => [ssl:ssl_option()],
           timeout => timeout(),
           async => pid(),
+          codecs => [{epgsql_codec:codec_mod(), any()}],
           replication => string()}.
 -else.
 -type connect_opts() :: [connect_option()].
@@ -148,16 +150,25 @@ connect(C, Host, Username, Password, Opts0) ->
     case epgsql_sock:sync_command(
            C, epgsql_cmd_connect, {Host, Username, Password, Opts}) of
         connected ->
-            case proplists:get_value(replication, Opts, undefined) of
-                undefined ->
-                    update_type_cache(C),
-                    {ok, C};
-                _ -> {ok, C} %% do not update update_type_cache if connection is in replication mode
-            end;
+            %% If following call fails for you, try to add {codecs, []} connect option
+            {ok, _} = maybe_update_typecache(C, Opts),
+            {ok, C};
         Error = {error, _} ->
             Error
     end.
 
+maybe_update_typecache(C, Opts) ->
+    maybe_update_typecache(C, proplists:get_value(replication, Opts), proplists:get_value(codecs, Opts)).
+
+maybe_update_typecache(C, undefined, undefined) ->
+    %% TODO: don't execute 'update_type_cache' when `codecs` is undefined.
+    %% This will break backward compatibility
+    update_type_cache(C);
+maybe_update_typecache(C, undefined, [_ | _] = Codecs) ->
+    update_type_cache(C, Codecs);
+maybe_update_typecache(_, _, _) ->
+    {ok, []}.
+
 update_type_cache(C) ->
     update_type_cache(C, [{epgsql_codec_hstore, []},
                           {epgsql_codec_postgis, []}]).

+ 16 - 14
src/epgsqla.erl

@@ -19,7 +19,7 @@
          close/2, close/3,
          sync/1,
          cancel/1,
-         complete_connect/2]).
+         complete_connect/3]).
 
 -include("epgsql.hrl").
 
@@ -48,9 +48,9 @@ connect(Host, Username, Password, Opts) ->
 -spec connect(epgsql:connection(), inet:ip_address() | inet:hostname(),
               string(), string(), [epgsql:connect_option()]) -> reference().
 connect(C, Host, Username, Password, Opts) ->
+    Opts1 = epgsql:to_proplist(Opts),
     complete_connect(
-      C, cast(
-           C, epgsql_cmd_connect, {Host, Username, Password, epgsql:to_proplist(Opts)})).
+      C, cast(C, epgsql_cmd_connect, {Host, Username, Password, Opts1}), Opts1).
 
 -spec close(epgsql:connection()) -> ok.
 close(C) ->
@@ -144,20 +144,22 @@ cancel(C) ->
 cast(C, Command, Args) ->
     epgsql_sock:async_command(C, cast, Command, Args).
 
-complete_connect(C, Ref) ->
+complete_connect(C, Ref, Opts) ->
     receive
         %% If we connect, then try and update the type cache.  When
         %% all is said and done, pass the result along as a message.
-        {C, Ref, Msg} ->
-            Retval =
-                case Msg of
-                    connected ->
-                        {ok, _} = epgsql:update_type_cache(C),
-                        {C, Ref, connected};
-                    {error, Error} ->
-                        {C, Ref, {error, Error}}
-                end,
-            self() ! Retval;
+        {C, Ref, connected} ->
+            case proplists:get_value(codecs, Opts) of
+                undefined ->
+                    {ok, _} = epgsql:update_type_cache(C);
+                [_|_] = Codecs ->
+                    {ok, _} = epgsql:update_type_cache(C, Codecs);
+                [] ->
+                    ok
+            end,
+            self() ! {C, Ref, connected};
+        {C, Ref, {error, _} = Err} ->
+            self() ! {C, Ref, Err};
         {'EXIT', C, Reason} ->
             self() ! {'EXIT', C, Reason}
     end,

+ 2 - 2
src/epgsqli.erl

@@ -47,9 +47,9 @@ connect(Host, Username, Password, Opts) ->
 -spec connect(epgsql:connection(), inet:ip_address() | inet:hostname(),
               string(), string(), [epgsql:connect_option()]) -> reference().
 connect(C, Host, Username, Password, Opts) ->
+    Opts1 = epgsql:to_proplist(Opts),
     epgsqla:complete_connect(
-      C, incremental(
-           C, epgsql_cmd_connect, {Host, Username, Password, epgsql:to_proplist(Opts)})).
+      C, incremental(C, epgsql_cmd_connect, {Host, Username, Password, Opts1}), Opts1).
 
 -spec close(epgsql:connection()) -> ok.
 close(C) ->