Current section

Files

Jump to
squirrel src squirrel.erl
Raw

src/squirrel.erl

-module(squirrel).
-compile([no_auto_import, nowarn_unused_vars, nowarn_unused_function, nowarn_nomatch]).
-export([main/0]).
-spec read_connection_options() -> squirrel@internal@database@postgres:connection_options().
read_connection_options() ->
Host = begin
_pipe = envoy_ffi:get(<<"PGHOST"/utf8>>),
gleam@result:unwrap(_pipe, <<"localhost"/utf8>>)
end,
User = begin
_pipe@1 = envoy_ffi:get(<<"PGUSER"/utf8>>),
gleam@result:unwrap(_pipe@1, <<"root"/utf8>>)
end,
Database = begin
_pipe@2 = envoy_ffi:get(<<"PGDATABASE"/utf8>>),
gleam@result:unwrap(_pipe@2, <<"database"/utf8>>)
end,
Password = begin
_pipe@3 = envoy_ffi:get(<<"PGPASSWORD"/utf8>>),
gleam@result:unwrap(_pipe@3, <<""/utf8>>)
end,
Port = begin
_pipe@4 = envoy_ffi:get(<<"PGPORT"/utf8>>),
_pipe@5 = gleam@result:then(_pipe@4, fun gleam@int:parse/1),
gleam@result:unwrap(_pipe@5, 5432)
end,
{connection_options, Host, Port, User, Password, Database, 1000}.
-spec walk(binary()) -> gleam@dict:dict(binary(), list(binary())).
walk(From) ->
case filepath:base_name(From) of
<<"sql"/utf8>> ->
_assert_subject = simplifile_erl:read_directory(From),
{ok, Files} = case _assert_subject of
{ok, _} -> _assert_subject;
_assert_fail ->
erlang:error(#{gleam_error => let_assert,
message => <<"Assertion pattern match failed"/utf8>>,
value => _assert_fail,
module => <<"squirrel"/utf8>>,
function => <<"walk"/utf8>>,
line => 83})
end,
Files@1 = (gleam@list:filter_map(
Files,
fun(File) ->
gleam@result:'try'(
filepath:extension(File),
fun(Extension) ->
gleam@bool:guard(
Extension /= <<"sql"/utf8>>,
{error, nil},
fun() ->
File_name = filepath:join(From, File),
case simplifile_erl:is_file(File_name) of
{ok, true} ->
{ok, File_name};
{ok, false} ->
{error, nil};
{error, _} ->
{error, nil}
end
end
)
end
)
end
)),
maps:from_list([{From, Files@1}]);
_ ->
_assert_subject@1 = simplifile_erl:read_directory(From),
{ok, Files@2} = case _assert_subject@1 of
{ok, _} -> _assert_subject@1;
_assert_fail@1 ->
erlang:error(#{gleam_error => let_assert,
message => <<"Assertion pattern match failed"/utf8>>,
value => _assert_fail@1,
module => <<"squirrel"/utf8>>,
function => <<"walk"/utf8>>,
line => 98})
end,
Directories = (gleam@list:filter_map(
Files@2,
fun(File@1) ->
File_name@1 = filepath:join(From, File@1),
case simplifile_erl:is_directory(File_name@1) of
{ok, true} ->
{ok, File_name@1};
{ok, false} ->
{error, nil};
{error, _} ->
{error, nil}
end
end
)),
_pipe = gleam@list:map(Directories, fun walk/1),
gleam@list:fold(_pipe, gleam@dict:new(), fun gleam@dict:merge/2)
end.
-spec pluralise(integer(), binary(), binary()) -> binary().
pluralise(Count, Singular, Plural) ->
case Count of
1 ->
Singular;
_ ->
Plural
end.
-spec flexible_string(binary()) -> glam@doc:document().
flexible_string(String) ->
_pipe = gleam@string:split(String, <<"\n"/utf8>>),
_pipe@1 = gleam@list:flat_map(
_pipe,
fun(_capture) -> gleam@string:split(_capture, <<" "/utf8>>) end
),
_pipe@2 = gleam@list:map(_pipe@1, fun glam@doc:from_string/1),
_pipe@3 = glam@doc:join(_pipe@2, {flex_break, <<" "/utf8>>, <<""/utf8>>}),
glam@doc:group(_pipe@3).
-spec text_with_header(binary(), binary()) -> glam@doc:document().
text_with_header(Header, Text) ->
_pipe@1 = [glam@doc:from_string(Header),
begin
_pipe = flexible_string(Text),
glam@doc:nest(_pipe, gleam@string:length(Header))
end],
_pipe@2 = glam@doc:concat(_pipe@1),
glam@doc:group(_pipe@2).
-spec pretty_report(
gleam@dict:dict(binary(), {integer(), list(squirrel@internal@error:error())})
) -> binary().
pretty_report(Dirs) ->
Width = begin
_pipe = term_size:columns(),
gleam@result:unwrap(_pipe, 80)
end,
{Ok@1, Errors@1} = (gleam@dict:fold(
Dirs,
{0, []},
fun(_use0, _, Result) ->
{All_ok, All_errors} = _use0,
{Ok, Errors} = Result,
{All_ok + Ok,
begin
_pipe@1 = Errors,
lists:append(_pipe@1, All_errors)
end}
end
)),
Errors_doc = begin
_pipe@2 = gleam@list:map(Errors@1, fun squirrel@internal@error:to_doc/1),
glam@doc:join(_pipe@2, glam@doc:lines(2))
end,
case {Ok@1, Errors@1} of
{0, [_ | _]} ->
glam@doc:to_string(Errors_doc, Width);
{0, []} ->
_pipe@3 = text_with_header(
<<"🐿️ "/utf8>>,
<<"I couldn't find any `*.sql` file to generate queries from"/utf8>>
),
_pipe@4 = glam@doc:to_string(_pipe@3, Width),
gleam_community@ansi:yellow(_pipe@4);
{N, []} ->
_pipe@5 = text_with_header(
<<"🐿️ "/utf8>>,
<<<<<<"Generated "/utf8, (gleam@int:to_string(N))/binary>>/binary,
" "/utf8>>/binary,
(pluralise(N, <<"query"/utf8>>, <<"queries"/utf8>>))/binary>>
),
_pipe@6 = glam@doc:to_string(_pipe@5, Width),
_pipe@7 = gleam_community@ansi:green(_pipe@6),
_pipe@8 = gleam@string:append(_pipe@7, <<"\n"/utf8>>),
gleam@string:append(
_pipe@8,
begin
_pipe@9 = text_with_header(
<<"🥜 "/utf8>>,
<<"Don't forget to run `gleam add decode gleam_pgo` if you haven't yet!"/utf8>>
),
_pipe@10 = glam@doc:to_string(_pipe@9, Width),
gleam_community@ansi:cyan(_pipe@10)
end
);
{N@1, [_ | _]} ->
_pipe@11 = [Errors_doc,
glam@doc:lines(2),
text_with_header(
<<"🥜 "/utf8>>,
<<<<<<"I could still generate "/utf8,
(gleam@int:to_string(N@1))/binary>>/binary,
" "/utf8>>/binary,
(pluralise(N@1, <<"query"/utf8>>, <<"queries"/utf8>>))/binary>>
)],
_pipe@12 = glam@doc:concat(_pipe@11),
glam@doc:to_string(_pipe@12, Width)
end.
-spec write_queries(list(squirrel@internal@query:typed_query()), binary()) -> {ok,
integer()} |
{error, squirrel@internal@error:error()}.
write_queries(Queries, File) ->
gleam@bool:guard(
Queries =:= [],
{ok, 0},
fun() ->
Directory = filepath:directory_name(File),
_ = simplifile:create_directory_all(Directory),
Imports = <<"import gleam/pgo\nimport decode\n"/utf8>>,
{Count@1, Code@1} = (gleam@list:fold(
Queries,
{0, Imports},
fun(_use0, Query) ->
{Count, Code} = _use0,
{Count + 1,
<<<<Code/binary, "\n"/utf8>>/binary,
(squirrel@internal@query:generate_code(
<<"v1.0.0"/utf8>>,
Query
))/binary>>}
end
)),
Try_write = begin
_pipe = simplifile:write(File, Code@1),
gleam@result:map_error(
_pipe,
fun(_capture) -> {cannot_write_to_file, File, _capture} end
)
end,
gleam@result:'try'(Try_write, fun(_) -> {ok, Count@1} end)
end
).
-spec run(
gleam@dict:dict(binary(), list(binary())),
squirrel@internal@database@postgres:connection_options()
) -> gleam@dict:dict(binary(), {integer(),
list(squirrel@internal@error:error())}).
run(Directories, Connection) ->
gleam@dict:map_values(
Directories,
fun(Directory, Files) ->
{Queries, Errors} = begin
_pipe = gleam@list:map(
Files,
fun squirrel@internal@query:from_file/1
),
gleam@result:partition(_pipe)
end,
{Queries@2, Errors@1} = case squirrel@internal@database@postgres:main(
Queries,
Connection
) of
{error, Error} ->
{[], [Error | Errors]};
{ok, {Queries@1, Type_errors}} ->
{Queries@1, lists:append(Errors, Type_errors)}
end,
Output_file = begin
_pipe@1 = filepath:directory_name(Directory),
filepath:join(_pipe@1, <<"sql.gleam"/utf8>>)
end,
case write_queries(Queries@2, Output_file) of
{ok, N} ->
{N, Errors@1};
{error, Error@1} ->
{erlang:length(Queries@2), [Error@1 | Errors@1]}
end
end
).
-spec main() -> nil.
main() ->
_pipe = walk(<<"src"/utf8>>),
_pipe@1 = run(_pipe, read_connection_options()),
_pipe@2 = pretty_report(_pipe@1),
gleam@io:println(_pipe@2).