-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, <<"postgres"/utf8>>) end, Project_name = begin _pipe@2 = squirrel@internal@project:name(), gleam@result:unwrap(_pipe@2, <<"database"/utf8>>) end, Database = begin _pipe@3 = envoy_ffi:get(<<"PGDATABASE"/utf8>>), gleam@result:unwrap(_pipe@3, Project_name) end, Password = begin _pipe@4 = envoy_ffi:get(<<"PGPASSWORD"/utf8>>), gleam@result:unwrap(_pipe@4, <<""/utf8>>) end, Port = begin _pipe@5 = envoy_ffi:get(<<"PGPORT"/utf8>>), _pipe@6 = gleam@result:then(_pipe@5, fun gleam@int:parse/1), gleam@result:unwrap(_pipe@6, 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 => 86}) 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 => 101}) 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), gleam_community@ansi:green(_pipe@6); {N@1, [_ | _]} -> _pipe@7 = [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@8 = glam@doc:concat(_pipe@7), glam@doc:to_string(_pipe@8, 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), {Count@1, Code@1, Imports@1} = begin Acc = {0, <<""/utf8>>, gleam@set:new()}, gleam@list:fold( Queries, Acc, fun(_use0, Query) -> {Count, Code, Imports} = _use0, {Query_code, Query_imports} = squirrel@internal@query:generate_code( <<"v1.2.0"/utf8>>, Query ), {Count + 1, <<<>/binary, Query_code/binary>>, begin _pipe = Imports, gleam@set:union(_pipe, Query_imports) end} end ) end, Imports@2 = begin _pipe@1 = gleam@set:to_list(Imports@1), _pipe@2 = gleam@list:sort(_pipe@1, fun gleam@string:compare/2), gleam@string:join(_pipe@2, <<"\n"/utf8>>) end, Code@2 = <<<>/binary, Code@1/binary>>, Try_write = begin _pipe@3 = simplifile:write(File, Code@2), gleam@result:map_error( _pipe@3, 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(squirrel@internal@project:src()), _pipe@1 = run(_pipe, read_connection_options()), _pipe@2 = pretty_report(_pipe@1), gleam@io:println(_pipe@2).