Packages
gleam_mongo
0.9.0
0.18.1
retired
0.18.0
retired
0.17.0
retired
0.16.0
retired
0.15.1
retired
0.15.0
retired
0.14.0
retired
0.13.0
retired
0.12.0
retired
0.11.0
retired
0.10.0
retired
0.9.0
retired
0.8.0
retired
0.7.0
retired
0.6.0
retired
0.5.0
retired
0.4.0
retired
0.3.0
0.2.0
retired
0.1.3
retired
0.1.2
retired
0.1.1
retired
0.1.0
retired
A mongodb driver for gleam
Retired package: Renamed - Republished as mungo
Current section
Files
Jump to
Current section
Files
src/mongo@client.erl
-module(mongo@client).
-compile(no_auto_import).
-export([connect/1, collection/2, execute/2]).
-export_type([connection_info/0, database/0, collection/0]).
-opaque connection_info() :: {connection_info,
binary(),
integer(),
binary(),
gleam@option:option({binary(), binary()}),
gleam@option:option(binary())}.
-type 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
{error, _try} -> {error, _try};
{ok, Info} ->
case Info of
{connection_info, Host, Port, Db, Auth, Auth_source} ->
case tcp:connect(Host, Port) of
{error, _try@1} -> {error, _try@1};
{ok, Socket} ->
case Auth of
none ->
{ok, {database, Socket, Db}};
{some, {Username, Password}} ->
case case Auth_source of
none ->
authenticate(
Socket,
Username,
Password,
Db
);
{some, Source} ->
authenticate(
Socket,
Username,
Password,
Source
)
end of
{error, _try@2} -> {error, _try@2};
{ok, _@1} ->
{ok, {database, Socket, Db}}
end
end
end
end
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 send_cmd(Socket, Name, Cmd) 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 authenticate(tcp:socket(), binary(), binary(), binary()) -> {ok, nil} |
{error, nil}.
authenticate(Socket, Username, Password, Auth_source) ->
First_payload = mongo@scram:first_payload(Username),
First = mongo@scram:first_message(First_payload),
case send_cmd(Socket, Auth_source, First) of
{error, _try} -> {error, _try};
{ok, Reply} ->
case mongo@scram:parse_first_reply(Reply) of
{error, _try@1} -> {error, _try@1};
{ok, {Server_params, Server_payload, Cid}} ->
case mongo@scram:second_message(
Server_params,
First_payload,
Server_payload,
Cid,
Password
) of
{error, _try@2} -> {error, _try@2};
{ok, {Second, Server_signature}} ->
case send_cmd(Socket, Auth_source, Second) of
{error, _try@3} -> {error, _try@3};
{ok, Reply@1} ->
case Reply@1 of
[{<<"ok"/utf8>>, {double, 0.0}} | _@1] ->
{error, nil};
Reply@2 ->
mongo@scram:parse_second_reply(
Reply@2,
Server_signature
)
end
end
end
end
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 => 108})
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 tcp:send(Socket, Packet) of
ok ->
case tcp:'receive'(Socket) of
{ok, Response} ->
<<_@1:168, Rest/bitstring>> = Response,
case bson:decode(Rest) of
{ok, Result} ->
{ok, Result};
{error, nil} ->
{error, nil}
end;
{error, nil} ->
{error, nil}
end;
_@2 ->
{error, nil}
end.
-spec parse_connection_string(binary()) -> {ok, connection_info()} |
{error, nil}.
parse_connection_string(Uri) ->
case gleam@uri:parse(Uri) of
{error, _try} -> {error, _try};
{ok, Parsed} ->
case erlang:element(2, Parsed) of
{some, <<"mongodb"/utf8>>} ->
case erlang:element(4, Parsed) of
{some, <<""/utf8>>} ->
{error, nil};
{some, Host} ->
Port = gleam@option:unwrap(
erlang:element(5, Parsed),
27017
),
case erlang:element(6, Parsed) of
<<""/utf8>> ->
{error, nil};
<<"/"/utf8>> ->
{error, nil};
Path ->
[_@1, Db] = gleam@string:split(
Path,
<<"/"/utf8>>
),
case gleam@uri:percent_decode(Db) of
{error, _try@1} -> {error, _try@1};
{ok, Db@1} ->
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 begin
_pipe = [Username,
Password],
gleam@list:map(
_pipe,
fun gleam@uri:percent_decode/1
)
end of
[{ok,
Username@1},
{ok,
Password@1}] ->
case erlang:element(
7,
Parsed
) of
{some,
Query} ->
case gleam@uri:parse_query(
Query
) of
{error, _try@2} -> {error, _try@2};
{ok, Opts} ->
case gleam@list:key_find(
Opts,
<<"authSource"/utf8>>
) of
{ok,
Auth_source} ->
_pipe@1 = {connection_info,
Host,
Port,
Db@1,
{some,
{Username@1,
Password@1}},
{some,
Auth_source}},
{ok,
_pipe@1};
{error,
nil} ->
_pipe@2 = {connection_info,
Host,
Port,
Db@1,
{some,
{Username@1,
Password@1}},
none},
{ok,
_pipe@2}
end
end;
none ->
_pipe@3 = {connection_info,
Host,
Port,
Db@1,
{some,
{Username@1,
Password@1}},
none},
{ok,
_pipe@3}
end;
_@4 ->
{error, nil}
end;
_@5 ->
{error, nil}
end;
none ->
_pipe@4 = {connection_info,
Host,
Port,
Db@1,
none,
none},
{ok, _pipe@4}
end
end
end;
none ->
{error, nil}
end;
{some, _@6} ->
{error, nil};
none ->
{error, nil}
end
end.