Current section
Files
Jump to
Current section
Files
src/m25@internal@cli.erl
-module(m25@internal@cli).
-compile([no_auto_import, nowarn_unused_vars, nowarn_unused_function, nowarn_nomatch]).
-define(FILEPATH, "src/m25/internal/cli.gleam").
-export([migrate_for_tests/1, run_cli/0]).
-if(?OTP_RELEASE >= 27).
-define(MODULEDOC(Str), -moduledoc(Str)).
-define(DOC(Str), -doc(Str)).
-else.
-define(MODULEDOC(Str), -compile([])).
-define(DOC(Str), -compile([])).
-endif.
?MODULEDOC(false).
-file("src/m25/internal/cli.gleam", 23).
?DOC(false).
-spec add_error_context(binary(), binary()) -> binary().
add_error_context(Error, Context) ->
<<<<Context/binary, ": "/utf8>>/binary, Error/binary>>.
-file("src/m25/internal/cli.gleam", 27).
?DOC(false).
-spec print(binary(), boolean()) -> nil.
print(Message, Silent) ->
case Silent of
false ->
gleam_stdlib:print_error(Message);
true ->
nil
end.
-file("src/m25/internal/cli.gleam", 34).
?DOC(false).
-spec println(binary(), boolean()) -> nil.
println(Message, Silent) ->
print(<<Message/binary, "\n"/utf8>>, Silent).
-file("src/m25/internal/cli.gleam", 38).
?DOC(false).
-spec check_m25_schema_exists(pog:connection()) -> {ok, boolean()} |
{error, binary()}.
check_m25_schema_exists(Tx) ->
Query_result = begin
_pipe = pog:'query'(
<<"select schema_name from information_schema.schemata where schema_name = 'm25'"/utf8>>
),
_pipe@1 = pog:returning(
_pipe,
begin
gleam@dynamic@decode:field(
0,
{decoder, fun gleam@dynamic@decode:decode_string/1},
fun(Value) -> gleam@dynamic@decode:success(Value) end
)
end
),
_pipe@2 = pog:execute(_pipe@1, Tx),
gleam@result:map_error(_pipe@2, fun gleam@string:inspect/1)
end,
gleam@result:'try'(
Query_result,
fun(Response) -> case erlang:element(3, Response) of
[_] ->
{ok, true};
[] ->
{ok, false};
_ ->
{error, <<"Too many rows"/utf8>>}
end end
).
-file("src/m25/internal/cli.gleam", 58).
?DOC(false).
-spec get_current_version(pog:connection()) -> {ok,
gleam@option:option(gleam@time@timestamp:timestamp())} |
{error, binary()}.
get_current_version(Tx) ->
Query_result = begin
_pipe = pog:'query'(
<<"select version::timestamp from m25.version order by version desc limit 1"/utf8>>
),
_pipe@1 = pog:returning(
_pipe,
begin
gleam@dynamic@decode:field(
0,
pog:timestamp_decoder(),
fun(Timestamp) ->
gleam@dynamic@decode:success(Timestamp)
end
)
end
),
_pipe@2 = pog:execute(_pipe@1, Tx),
gleam@result:map_error(_pipe@2, fun gleam@string:inspect/1)
end,
gleam@result:'try'(
Query_result,
fun(Response) -> case erlang:element(3, Response) of
[] ->
{ok, none};
[Version] ->
{ok, {some, Version}};
_ ->
{error, <<"Too many rows"/utf8>>}
end end
).
-file("src/m25/internal/cli.gleam", 80).
?DOC(false).
-spec get_migrations() -> {ok, list(binary())} | {error, binary()}.
get_migrations() ->
gleam@result:'try'(
begin
_pipe = gleam_erlang_ffi:priv_directory(<<"m25"/utf8>>),
gleam@result:replace_error(
_pipe,
<<"Couldn't get priv directory"/utf8>>
)
end,
fun(Priv) ->
Directory@1 = case begin
_pipe@1 = [Priv, <<"migrations"/utf8>>],
gleam@list:reduce(_pipe@1, fun filepath:join/2)
end of
{ok, Directory} -> Directory;
_assert_fail ->
erlang:error(#{gleam_error => let_assert,
message => <<"Pattern match failed, no pattern matched the value."/utf8>>,
file => <<?FILEPATH/utf8>>,
module => <<"m25/internal/cli"/utf8>>,
function => <<"get_migrations"/utf8>>,
line => 86,
value => _assert_fail,
start => 1993,
'end' => 2078,
pattern_start => 2004,
pattern_end => 2017})
end,
_pipe@2 = simplifile:get_files(Directory@1),
gleam@result:map_error(_pipe@2, fun(Err) -> _pipe@3 = Err,
_pipe@4 = gleam@string:inspect(_pipe@3),
add_error_context(
_pipe@4,
<<"Unable to get files in priv directory"/utf8>>
) end)
end
).
-file("src/m25/internal/cli.gleam", 98).
?DOC(false).
-spec version_from_filename(binary()) -> gleam@time@timestamp:timestamp().
version_from_filename(Filename) ->
Filename@2 = case begin
_pipe = Filename,
_pipe@1 = filepath:split(_pipe),
gleam@list:last(_pipe@1)
end of
{ok, Filename@1} -> Filename@1;
_assert_fail ->
erlang:error(#{gleam_error => let_assert,
message => <<"Pattern match failed, no pattern matched the value."/utf8>>,
file => <<?FILEPATH/utf8>>,
module => <<"m25/internal/cli"/utf8>>,
function => <<"version_from_filename"/utf8>>,
line => 99,
value => _assert_fail,
start => 2320,
'end' => 2385,
pattern_start => 2331,
pattern_end => 2343})
end,
Version_string@1 = case begin
_pipe@2 = Filename@2,
_pipe@3 = gleam@string:split(_pipe@2, <<"_"/utf8>>),
gleam@list:first(_pipe@3)
end of
{ok, Version_string} -> Version_string;
_assert_fail@1 ->
erlang:error(#{gleam_error => let_assert,
message => <<"Pattern match failed, no pattern matched the value."/utf8>>,
file => <<?FILEPATH/utf8>>,
module => <<"m25/internal/cli"/utf8>>,
function => <<"version_from_filename"/utf8>>,
line => 100,
value => _assert_fail@1,
start => 2388,
'end' => 2463,
pattern_start => 2399,
pattern_end => 2417})
end,
Version@1 = case tempo@datetime:parse(
<<Version_string@1/binary, "Z"/utf8>>,
{custom, <<"YYYYMMDDHHmmssZ"/utf8>>}
) of
{ok, Version} -> Version;
_assert_fail@2 ->
erlang:error(#{gleam_error => let_assert,
message => <<"Pattern match failed, no pattern matched the value."/utf8>>,
file => <<?FILEPATH/utf8>>,
module => <<"m25/internal/cli"/utf8>>,
function => <<"version_from_filename"/utf8>>,
line => 102,
value => _assert_fail@2,
start => 2534,
'end' => 2633,
pattern_start => 2545,
pattern_end => 2556})
end,
tempo@datetime:to_timestamp(Version@1).
-file("src/m25/internal/cli.gleam", 107).
?DOC(false).
-spec get_migrations_to_apply(
gleam@option:option(gleam@time@timestamp:timestamp())
) -> {ok, gleam@option:option(binary())} | {error, binary()}.
get_migrations_to_apply(Current_version) ->
gleam@result:'try'(
begin
_pipe = get_migrations(),
gleam@result:map_error(
_pipe,
fun(_capture) ->
add_error_context(
_capture,
<<"Failed to get migrations for m25 tables"/utf8>>
)
end
)
end,
fun(Files) ->
Files_to_apply = case Current_version of
none ->
Files;
{some, Current_version@1} ->
_pipe@1 = Files,
gleam@list:filter(
_pipe@1,
fun(File) ->
gleam@time@timestamp:compare(
version_from_filename(File),
Current_version@1
)
=:= gt
end
)
end,
gleam@bool:guard(case Files_to_apply of
[] ->
true;
_ ->
false
end, {ok, none}, fun() ->
gleam@result:'try'(
begin
_pipe@2 = Files_to_apply,
_pipe@3 = gleam@list:try_map(
_pipe@2,
fun simplifile:read/1
),
_pipe@4 = gleam@result:map(
_pipe@3,
fun(_capture@1) ->
gleam@string:join(_capture@1, <<"\n"/utf8>>)
end
),
gleam@result:map_error(
_pipe@4,
fun(Err) ->
add_error_context(
gleam@string:inspect(Err),
<<"Failed to read migrations"/utf8>>
)
end
)
end,
fun(Migration_sql) ->
Latest_migration@1 = case gleam@list:last(
Files_to_apply
) of
{ok, Latest_migration} -> Latest_migration;
_assert_fail ->
erlang:error(#{gleam_error => let_assert,
message => <<"Pattern match failed, no pattern matched the value."/utf8>>,
file => <<?FILEPATH/utf8>>,
module => <<"m25/internal/cli"/utf8>>,
function => <<"get_migrations_to_apply"/utf8>>,
line => 146,
value => _assert_fail,
start => 3631,
'end' => 3690,
pattern_start => 3642,
pattern_end => 3662})
end,
New_version = version_from_filename(
Latest_migration@1
),
New_version_sql = <<<<"insert into m25.version (version)
values (timestamptz '"/utf8,
(begin
_pipe@5 = New_version,
gleam@time@timestamp:to_rfc3339(
_pipe@5,
{duration, 0, 0}
)
end)/binary>>/binary,
"');\n"/utf8>>,
{ok,
{some,
<<<<Migration_sql/binary, "\n"/utf8>>/binary,
New_version_sql/binary>>}}
end
)
end)
end
).
-file("src/m25/internal/cli.gleam", 157).
?DOC(false).
-spec apply_migrations(pog:connection(), binary(), boolean()) -> {ok, nil} |
{error, binary()}.
apply_migrations(Tx, Migration_sql, Silent) ->
print(<<"Applying migrations for m25... "/utf8>>, Silent),
gleam@result:'try'(
begin
_pipe@1 = gleam@string:last(
begin
_pipe = Migration_sql,
gleam@string:trim_end(_pipe)
end
),
gleam@result:replace_error(_pipe@1, <<"Empty migration file"/utf8>>)
end,
fun(Last_char) ->
Sql = case Last_char of
<<";"/utf8>> ->
Migration_sql;
_ ->
<<Migration_sql/binary, ";"/utf8>>
end,
Sql@1 = <<<<"do $m25migration$ begin "/utf8, Sql/binary>>/binary,
" end;$m25migration$"/utf8>>,
Query_result = begin
_pipe@2 = pog:'query'(Sql@1),
_pipe@3 = pog:execute(_pipe@2, Tx),
gleam@result:map_error(_pipe@3, fun gleam@string:inspect/1)
end,
gleam@result:'try'(
Query_result,
fun(_) ->
println(<<"ok."/utf8>>, Silent),
{ok, nil}
end
)
end
).
-file("src/m25/internal/cli.gleam", 187).
?DOC(false).
-spec handle_migration(pog:connection(), boolean(), boolean()) -> {ok, nil} |
{error, binary()}.
handle_migration(Tx, Apply, Silent) ->
print(<<"Checking schema... "/utf8>>, Silent),
gleam@result:'try'(
begin
_pipe = check_m25_schema_exists(Tx),
gleam@result:map_error(
_pipe,
fun(_capture) ->
add_error_context(
_capture,
<<"Unable to check if 'm25' schema exists"/utf8>>
)
end
)
end,
fun(Schema_exists) ->
println(<<"ok."/utf8>>, Silent),
print(<<"Checking current version of m25 tables... "/utf8>>, Silent),
Version_result = case Schema_exists of
false ->
{ok, none};
true ->
_pipe@1 = get_current_version(Tx),
gleam@result:map_error(
_pipe@1,
fun(_capture@1) ->
add_error_context(
_capture@1,
<<"Unable to check m25 table version"/utf8>>
)
end
)
end,
gleam@result:'try'(
Version_result,
fun(Current_version) ->
println(
<<"ok. Current version: "/utf8,
(begin
_pipe@2 = Current_version,
_pipe@3 = gleam@option:map(
_pipe@2,
fun(_capture@2) ->
gleam@time@timestamp:to_rfc3339(
_capture@2,
{duration, 0, 0}
)
end
),
gleam@option:unwrap(_pipe@3, <<"none"/utf8>>)
end)/binary>>,
Silent
),
print(
<<"Getting migrations for m25 tables... "/utf8>>,
Silent
),
gleam@result:'try'(
begin
_pipe@4 = get_migrations_to_apply(Current_version),
gleam@result:map_error(
_pipe@4,
fun(_capture@3) ->
add_error_context(
_capture@3,
<<"Failed to get migrations to apply for m25 tables"/utf8>>
)
end
)
end,
fun(Migration_sql) ->
println(<<"ok."/utf8>>, Silent),
case Migration_sql of
none ->
println(
<<"No migrations to apply for m25 tables\n"/utf8>>,
Silent
),
{ok, nil};
{some, Migration_sql@1} ->
case Apply of
true ->
_pipe@5 = apply_migrations(
Tx,
Migration_sql@1,
Silent
),
gleam@result:map_error(
_pipe@5,
fun(_capture@4) ->
add_error_context(
_capture@4,
<<"Failed to apply migrations for m25 tables"/utf8>>
)
end
);
false ->
gleam_stdlib:println(
Migration_sql@1
),
{ok, nil}
end
end
end
)
end
)
end
).
-file("src/m25/internal/cli.gleam", 254).
?DOC(false).
-spec migrate_for_tests(pog:connection()) -> {ok, nil} | {error, binary()}.
migrate_for_tests(Tx) ->
handle_migration(Tx, true, true).
-file("src/m25/internal/cli.gleam", 258).
?DOC(false).
-spec connection_string_flag() -> glint:flag(binary()).
connection_string_flag() ->
_pipe = glint:string_flag(<<"addr"/utf8>>),
_pipe@1 = glint:flag_help(
_pipe,
<<"The connection string for your Postgres database"/utf8>>
),
glint:flag_default(
_pipe@1,
<<"postgresql://postgres:postgres@localhost:5432/postgres"/utf8>>
).
-file("src/m25/internal/cli.gleam", 266).
?DOC(false).
-spec apply_flag() -> glint:flag(boolean()).
apply_flag() ->
_pipe = glint:bool_flag(<<"apply"/utf8>>),
_pipe@1 = glint:flag_help(
_pipe,
<<"Apply migrations instead of just printing them"/utf8>>
),
glint:flag_default(_pipe@1, false).
-file("src/m25/internal/cli.gleam", 272).
?DOC(false).
-spec silent_flag() -> glint:flag(boolean()).
silent_flag() ->
_pipe = glint:bool_flag(<<"silent"/utf8>>),
_pipe@1 = glint:flag_help(_pipe, <<"Don't print messages to stderr"/utf8>>),
glint:flag_default(_pipe@1, false).
-file("src/m25/internal/cli.gleam", 278).
?DOC(false).
-spec migrate_command() -> glint:command({ok, nil} | {error, snag:snag()}).
migrate_command() ->
glint:command_help(
<<"Migrate M25 modules in your Postgres database"/utf8>>,
fun() ->
glint:flag(
connection_string_flag(),
fun(Connection_string_arg) ->
glint:flag(
apply_flag(),
fun(Apply_flag) ->
glint:flag(
silent_flag(),
fun(Silent_flag) ->
glint:command(
fun(_, _, Flags) ->
gleam@result:'try'(
Connection_string_arg(Flags),
fun(Connection_string) ->
gleam@result:'try'(
Apply_flag(Flags),
fun(Apply) ->
gleam@result:'try'(
Silent_flag(
Flags
),
fun(Silent) ->
Pool_name = gleam_erlang_ffi:new_name(
<<"m25_migrations"/utf8>>
),
gleam@result:'try'(
begin
_pipe = pog:url_config(
Pool_name,
Connection_string
),
gleam@result:replace_error(
_pipe,
{snag,
<<"Invalid Postgres connection string"/utf8>>,
[<<"invalid connection string"/utf8>>]}
)
end,
fun(
Config
) ->
Conn@1 = case pog:start(
Config
) of
{ok,
{started,
_,
Conn}} -> Conn;
_assert_fail ->
erlang:error(
#{gleam_error => let_assert,
message => <<"Pattern match failed, no pattern matched the value."/utf8>>,
file => <<?FILEPATH/utf8>>,
module => <<"m25/internal/cli"/utf8>>,
function => <<"migrate_command"/utf8>>,
line => 300,
value => _assert_fail,
start => 7776,
'end' => 7833,
pattern_start => 7787,
pattern_end => 7813}
)
end,
Transaction_result = pog:transaction(
Conn@1,
fun(
Tx
) ->
gleam@result:'try'(
handle_migration(
Tx,
Apply,
Silent
),
fun(
_
) ->
case Apply of
true ->
println(
<<"\nSuccess! Applied migrations for m25"/utf8>>,
Silent
);
false ->
nil
end,
{ok,
nil}
end
)
end
),
case Transaction_result of
{ok,
_} ->
{ok,
nil};
{error,
{transaction_rolled_back,
Msg}} ->
{error,
{snag,
Msg,
[<<"transaction rolled back"/utf8>>]}};
{error,
{transaction_query_error,
Err}} ->
{error,
{snag,
<<"Query error: "/utf8,
(gleam@string:inspect(
Err
))/binary>>,
[<<"query error"/utf8>>]}}
end
end
)
end
)
end
)
end
)
end
)
end
)
end
)
end
)
end
).
-file("src/m25/internal/cli.gleam", 324).
?DOC(false).
-spec run_cli() -> nil.
run_cli() ->
Cli = begin
_pipe = glint:new(),
_pipe@1 = glint:with_name(_pipe, <<"m25"/utf8>>),
_pipe@2 = glint:as_module(_pipe@1),
_pipe@3 = glint:pretty_help(_pipe@2, glint:default_pretty_help()),
glint:add(_pipe@3, [<<"migrate"/utf8>>], migrate_command())
end,
glint:run_and_handle(
Cli,
erlang:element(4, argv:load()),
fun(Cli_result) ->
gleam@result:map_error(
Cli_result,
fun(Errors) ->
println(
<<"Command failed with an error: "/utf8,
(erlang:element(2, Errors))/binary>>,
false
)
end
)
end
).