Current section
Files
Jump to
Current section
Files
src/refrakt@migrate.erl
-module(refrakt@migrate).
-compile([no_auto_import, nowarn_unused_vars, nowarn_unused_function, nowarn_nomatch, inline]).
-define(FILEPATH, "src/refrakt/migrate.gleam").
-export([run_from_directory/3]).
-export_type([migration/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.
-type migration() :: {migration, integer(), binary(), binary(), binary()}.
-file("src/refrakt/migrate.gleam", 79).
-spec parse_migration(binary(), binary()) -> {ok, migration()} | {error, nil}.
parse_migration(Dir, Filename) ->
Parts = gleam@string:split(Filename, <<"_"/utf8>>),
case Parts of
[Num_str | Rest] ->
case gleam_stdlib:parse_int(Num_str) of
{ok, Num} ->
Name = begin
_pipe = Rest,
_pipe@1 = gleam@string:join(_pipe, <<"_"/utf8>>),
gleam@string:replace(
_pipe@1,
<<".sql"/utf8>>,
<<""/utf8>>
)
end,
case simplifile:read(
<<<<Dir/binary, "/"/utf8>>/binary, Filename/binary>>
) of
{ok, Sql} ->
{ok, {migration, Num, Name, Filename, Sql}};
{error, _} ->
{error, nil}
end;
{error, _} ->
{error, nil}
end;
_ ->
{error, nil}
end.
-file("src/refrakt/migrate.gleam", 107).
-spec apply_migrations(
list(migration()),
fun((binary()) -> {ok, nil} | {error, binary()})
) -> {ok, nil} | {error, binary()}.
apply_migrations(Migrations, Db_execute) ->
case Migrations of
[] ->
{ok, nil};
[Migration | Rest] ->
gleam_stdlib:println(
<<<<" "/utf8, (erlang:element(4, Migration))/binary>>/binary,
" ..."/utf8>>
),
gleam@result:'try'(
begin
_pipe = Db_execute(erlang:element(5, Migration)),
gleam@result:map_error(
_pipe,
fun(E) ->
<<<<<<"Migration "/utf8,
(erlang:element(4, Migration))/binary>>/binary,
" failed: "/utf8>>/binary,
E/binary>>
end
)
end,
fun(_) ->
gleam@result:'try'(
Db_execute(
<<<<"INSERT INTO _migrations (name) VALUES ('"/utf8,
(erlang:element(4, Migration))/binary>>/binary,
"')"/utf8>>
),
fun(_) ->
gleam_stdlib:println(
<<<<" "/utf8,
(erlang:element(4, Migration))/binary>>/binary,
" ✓"/utf8>>
),
apply_migrations(Rest, Db_execute)
end
)
end
)
end.
-file("src/refrakt/migrate.gleam", 33).
?DOC(
" Run all pending migrations in a directory.\n"
" Returns the number of migrations applied.\n"
).
-spec run_from_directory(
fun((binary()) -> {ok, nil} | {error, binary()}),
fun((binary()) -> {ok, list(binary())} | {error, binary()}),
binary()
) -> {ok, integer()} | {error, binary()}.
run_from_directory(Db_execute, Db_query_strings, Migrations_dir) ->
gleam@result:'try'(
Db_execute(
<<"CREATE TABLE IF NOT EXISTS _migrations (
name TEXT PRIMARY KEY,
applied_at TIMESTAMPTZ NOT NULL DEFAULT NOW()
)"/utf8>>
),
fun(_) ->
gleam@result:'try'(
Db_query_strings(
<<"SELECT name FROM _migrations ORDER BY name"/utf8>>
),
fun(Applied) ->
gleam@result:'try'(
begin
_pipe = simplifile_erl:read_directory(
Migrations_dir
),
gleam@result:replace_error(
_pipe,
<<"Could not read migrations directory: "/utf8,
Migrations_dir/binary>>
)
end,
fun(Files) ->
Migrations = begin
_pipe@1 = Files,
_pipe@2 = gleam@list:filter(
_pipe@1,
fun(F) ->
gleam_stdlib:string_ends_with(
F,
<<".sql"/utf8>>
)
end
),
_pipe@3 = gleam@list:filter_map(
_pipe@2,
fun(Filename) ->
parse_migration(
Migrations_dir,
Filename
)
end
),
gleam@list:sort(
_pipe@3,
fun(A, B) ->
gleam@int:compare(
erlang:element(2, A),
erlang:element(2, B)
)
end
)
end,
Pending = begin
_pipe@4 = Migrations,
gleam@list:filter(
_pipe@4,
fun(M) ->
not gleam@list:contains(
Applied,
erlang:element(4, M)
)
end
)
end,
gleam@result:'try'(
apply_migrations(Pending, Db_execute),
fun(_) -> {ok, erlang:length(Pending)} end
)
end
)
end
)
end
).