Current section

Files

Jump to
gleam_mongo src mongo@client.erl
Raw

src/mongo@client.erl

-module(mongo@client).
-compile(no_auto_import).
-export([connect/1, collection/2, execute/2]).
-export_type([auth/0, connection_info/0, database/0, collection/0]).
-opaque auth() :: {auth, binary(), binary()}.
-opaque connection_info() :: {connection_info,
binary(),
integer(),
binary(),
gleam@option:option(auth()),
gleam@option:option(binary())}.
-opaque database() :: {database, tcp:socket(), binary()}.
-type collection() :: {collection, database(), binary()}.
-spec connect(binary()) -> {ok, database()} | {error, nil}.
connect(Uri) ->
case parse_connection_string(Uri) of
{ok, Info} ->
case Info of
{connection_info, Host, Port, Db, _@1, _@2} ->
case tcp:connect(Host, Port) of
{ok, Socket} ->
{ok, {database, Socket, Db}};
{error, _@3} ->
{error, nil}
end
end;
{error, nil} ->
{error, nil}
end.
-spec collection(database(), binary()) -> collection().
collection(Db, Name) ->
{collection, Db, Name}.
-spec execute(collection(), bson@types:value()) -> {ok,
list({binary(),
bson@types:value()})} |
{error, {integer(), binary()}}.
execute(Collection, Cmd) ->
case erlang:element(2, Collection) of
{database, Socket, Name} ->
case begin
_pipe = Socket,
send_cmd(_pipe, Name, Cmd)
end of
{ok,
[{<<"ok"/utf8>>, {double, 0.0}},
{<<"errmsg"/utf8>>, {str, Msg}},
{<<"code"/utf8>>, {integer, Code}},
{<<"codeName"/utf8>>, _@1}]} ->
{error, {Code, Msg}};
{ok, Result} ->
{ok, Result};
{error, nil} ->
{error, {-2, <<""/utf8>>}}
end
end.
-spec parse_connection_string(binary()) -> {ok, connection_info()} |
{error, nil}.
parse_connection_string(Uri) ->
case gleam@uri:parse(Uri) of
{ok, Parsed} ->
case erlang:element(2, Parsed) of
{some, <<"mongodb"/utf8>>} ->
case erlang:element(4, Parsed) of
{some, <<""/utf8>>} ->
{error, nil};
{some, Host} ->
Port = begin
_pipe = erlang:element(5, Parsed),
gleam@option:unwrap(_pipe, 27017)
end,
case erlang:element(6, Parsed) of
<<""/utf8>> ->
{error, nil};
<<"/"/utf8>> ->
{error, nil};
Path ->
[_@1, Db] = gleam@string:split(
Path,
<<"/"/utf8>>
),
case erlang:element(3, Parsed) of
{some, Userinfo} ->
case gleam@string:split(
Userinfo,
<<":"/utf8>>
) of
[<<""/utf8>>, _@2] ->
{error, nil};
[_@3, <<""/utf8>>] ->
{error, nil};
[Username, Password] ->
case erlang:element(
7,
Parsed
) of
{some, Query} ->
case begin
_pipe@1 = Query,
gleam@uri:parse_query(
_pipe@1
)
end of
{ok, Opts} ->
case gleam@list:key_find(
Opts,
<<"authSource"/utf8>>
) of
{ok,
Auth_source} ->
{ok,
{connection_info,
Host,
Port,
Db,
{some,
{auth,
Username,
Password}},
{some,
Auth_source}}};
{error,
nil} ->
{ok,
{connection_info,
Host,
Port,
Db,
{some,
{auth,
Username,
Password}},
none}}
end;
{error, nil} ->
{error, nil}
end;
none ->
{ok,
{connection_info,
Host,
Port,
Db,
{some,
{auth,
Username,
Password}},
none}}
end;
_@4 ->
{error, nil}
end;
none ->
{ok,
{connection_info,
Host,
Port,
Db,
none,
none}}
end
end;
none ->
{error, nil}
end;
{some, _@5} ->
{error, nil};
none ->
{error, nil}
end;
{error, nil} ->
{error, nil}
end.
-spec send_cmd(tcp:socket(), binary(), bson@types:value()) -> {ok,
list({binary(),
bson@types:value()})} |
{error, nil}.
send_cmd(Socket, Db, Cmd) ->
{document, Cmd@2} = case Cmd of
{document, Cmd@1} -> {document, Cmd@1};
_try ->
erlang:error(#{gleam_error => assert,
message => <<"Assertion pattern match failed"/utf8>>,
value => _try,
module => <<"mongo/client"/utf8>>,
function => <<"send_cmd"/utf8>>,
line => 160})
end,
Cmd@3 = gleam@list:append(Cmd@2, [{<<"$db"/utf8>>, {str, Db}}]),
Encoded = bson:encode(Cmd@3),
Size = gleam@bit_string:byte_size(Encoded) + 21,
Packet = begin
_pipe = [<<Size:32/little, 0:32, 0:32, 2013:32/little, 0:32, 0>>,
Encoded],
gleam@bit_string:concat(_pipe)
end,
case begin
_pipe@1 = Socket,
tcp:send(_pipe@1, Packet)
end of
ok ->
case begin
_pipe@2 = Socket,
tcp:'receive'(_pipe@2)
end of
{ok, Response} ->
<<_@1:168, Rest/bitstring>> = Response,
Rest,
case bson:decode(Rest) of
{ok, Result} ->
{ok, Result};
{error, nil} ->
{error, nil}
end;
{error, nil} ->
{error, nil}
end;
_@2 ->
{error, nil}
end.