src/surreal_config.erl

%%% @doc Module for advanced configs.
%%%
%%% This module allows you to set configs and use them with calling one function.
-module(surreal_config).

-type config_value() ::
    secure
    | link
    | {name, atom()}
    | {host, string()}
    | {port, integer()}
    | {signin, {string(), string()}}
    | {use, {string(), string()}}.

-type config() :: list(config_value()).

-export([child_spec/1, load/1]).

%% @doc Child specifications for Surreal connection.
-spec child_spec(Config :: config()) -> supervisor:child_spec().
child_spec(Config) ->
    case proplists:get_value(name, Config) of
        undefined ->
            erlang:error("Please provide a name for child specification");
        Name ->
            #{
                id => Name,
                start => {surreal_config, load, [Config]}
            }
    end.

%% @doc Start client from config.
-spec load(Config :: config()) ->
    {ok, pid()}.
load(Config) ->
    case load_piece({start, Config}) of
        {ok, Pid} ->
            load_piece({signin, Pid, Config}),
            load_piece({use, Pid, Config}),

            {ok, Pid};
        Other ->
            Other
    end.

%%% -------------------------------------------
%%% Following functions are for internal usage.
%%% -------------------------------------------

%% @private
load_piece({protocol, Config}) ->
    case proplists:is_defined(secure, Config) of
        true ->
            "wss";
        false ->
            "ws"
    end;
load_piece({url, Config}) ->
    WebSocketProtocol = load_piece({protocol, Config}),
    WebSocketHost = proplists:get_value(host, Config),
    WebSocketUrl =
        case proplists:get_value(port, Config) of
            undefined ->
                io_lib:format("~s://~s", [WebSocketProtocol, WebSocketHost]);
            Port ->
                io_lib:format("~s://~s:~b", [WebSocketProtocol, WebSocketHost, Port])
        end,

    lists:flatten(WebSocketUrl);
load_piece({start, Config}) ->
    WebSocketUrl = load_piece({url, Config}),

    case proplists:is_defined(link, Config) of
        true ->
            case proplists:get_value(name, Config) of
                undefined ->
                    gen_server:start_link(surreal_gen_server, [WebSocketUrl], []);
                Name ->
                    gen_server:start_link({local, Name}, surreal_gen_server, [WebSocketUrl], [])
            end;
        false ->
            case proplists:get_value(name, Config) of
                undefined ->
                    gen_server:start(surreal_gen_server, [WebSocketUrl], []);
                Name ->
                    gen_server:start({local, Name}, surreal_gen_server, [WebSocketUrl], [])
            end
    end;
load_piece({signin, Pid, Config}) ->
    case proplists:get_value(signin, Config) of
        {User, Pass} ->
            surreal:signin(Pid, User, Pass);
        _ ->
            noop
    end;
load_piece({use, Pid, Config}) ->
    case proplists:get_value(use, Config) of
        {Namespace, Database} ->
            surreal:use(Pid, Namespace, Database);
        _ ->
            noop
    end.