Current section
Files
Jump to
Current section
Files
src/cigogne.erl
-module(cigogne).
-compile([no_auto_import, nowarn_unused_vars, nowarn_unused_function, nowarn_nomatch]).
-define(FILEPATH, "src/cigogne.gleam").
-export([new_migration/2, apply_migration/2, apply_next_migration/1, execute_migrations_to_last/1, roll_back_migration/2, execute_n_migrations/2, get_migrations/1, get_schema/1, update_schema/1, print_error/1, apply_migration_if_not_applied/2, is_zero_migration/1, roll_back_previous_migration/1, create_migration_engine/1, create_zero_migration/3, main/0]).
-export_type([schema_data/0, migration_engine/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 schema_data() :: {schema_data, boolean(), binary()}.
-opaque migration_engine() :: {migration_engine,
cigogne@internal@database:database_data(),
schema_data(),
list(cigogne@types:migration()),
list(cigogne@types:migration())}.
-file("src/cigogne.gleam", 91).
-spec cli_to_connection_config(cigogne@internal@cli:config_options()) -> cigogne@types:connection_config().
cli_to_connection_config(Cli_config) ->
case erlang:element(2, Cli_config) of
{some, Url} ->
{url_config, Url};
none ->
User = begin
_pipe = erlang:element(4, Cli_config),
gleam@option:unwrap(_pipe, <<"postgres"/utf8>>)
end,
Password = begin
_pipe@1 = erlang:element(5, Cli_config),
gleam@option:unwrap(_pipe@1, <<"postgres"/utf8>>)
end,
Host = begin
_pipe@2 = erlang:element(3, Cli_config),
gleam@option:unwrap(_pipe@2, <<"localhost"/utf8>>)
end,
Port = begin
_pipe@3 = erlang:element(6, Cli_config),
gleam@option:unwrap(_pipe@3, 5432)
end,
Db_name = begin
_pipe@4 = erlang:element(7, Cli_config),
gleam@option:unwrap(_pipe@4, <<"postgres"/utf8>>)
end,
Url@1 = <<<<<<<<<<<<<<<<<<"postgresql://"/utf8, User/binary>>/binary,
":"/utf8>>/binary,
Password/binary>>/binary,
"@"/utf8>>/binary,
Host/binary>>/binary,
":"/utf8>>/binary,
(erlang:integer_to_binary(Port))/binary>>/binary,
"/"/utf8>>/binary,
Db_name/binary>>,
{url_config, Url@1}
end.
-file("src/cigogne.gleam", 165).
?DOC(" Create a new migration file in the specified folder with the provided name.\n").
-spec new_migration(binary(), binary()) -> {ok, nil} |
{error, cigogne@types:migrate_error()}.
new_migration(Migrations_folder, Name) ->
gleam@result:map(
cigogne@internal@fs:create_new_migration_file(
Migrations_folder,
gleam@time@timestamp:system_time(),
Name
),
fun(Path) ->
gleam_stdlib:println(
<<"Migration file created : "/utf8, Path/binary>>
)
end
).
-file("src/cigogne.gleam", 223).
?DOC(" Apply a migration to the database.\n").
-spec apply_migration(migration_engine(), cigogne@types:migration()) -> {ok,
nil} |
{error, cigogne@types:migrate_error()}.
apply_migration(Engine, Migration) ->
gleam_stdlib:println(
<<"\nApplying migration "/utf8,
(cigogne@internal@migrations_utils:format_migration_name(Migration))/binary>>
),
_pipe = cigogne@internal@database:apply_migration(
erlang:element(2, Engine),
Migration
),
gleam@result:map(
_pipe,
fun(_) ->
gleam_stdlib:println(
<<"Migration applied : "/utf8,
(cigogne@internal@migrations_utils:format_migration_name(
Migration
))/binary>>
)
end
).
-file("src/cigogne.gleam", 178).
?DOC(" Apply the next migration that wasn't applied yet.\n").
-spec apply_next_migration(migration_engine()) -> {ok, nil} |
{error, cigogne@types:migrate_error()}.
apply_next_migration(Engine) ->
gleam@result:'try'(
cigogne@internal@migrations_utils:find_first_non_applied_migration(
erlang:element(5, Engine),
erlang:element(4, Engine)
),
fun(Migration) -> apply_migration(Engine, Migration) end
).
-file("src/cigogne.gleam", 215).
?DOC(" Apply migrations until we reach the last defined migration.\n").
-spec execute_migrations_to_last(migration_engine()) -> {ok, nil} |
{error, cigogne@types:migrate_error()}.
execute_migrations_to_last(Engine) ->
_pipe = cigogne@internal@migrations_utils:find_all_non_applied_migration(
erlang:element(5, Engine),
erlang:element(4, Engine)
),
gleam@result:'try'(
_pipe,
fun(_capture) ->
gleam@list:try_each(
_capture,
fun(_capture@1) -> apply_migration(Engine, _capture@1) end
)
end
).
-file("src/cigogne.gleam", 241).
?DOC(" Roll back a migration from the database.\n").
-spec roll_back_migration(migration_engine(), cigogne@types:migration()) -> {ok,
nil} |
{error, cigogne@types:migrate_error()}.
roll_back_migration(Engine, Migration) ->
gleam_stdlib:println(
<<"\nRolling back migration "/utf8,
(cigogne@internal@migrations_utils:format_migration_name(Migration))/binary>>
),
_pipe = cigogne@internal@database:rollback_migration(
erlang:element(2, Engine),
Migration
),
gleam@result:map(
_pipe,
fun(_) ->
gleam_stdlib:println(
<<"Migration rolled back : "/utf8,
(cigogne@internal@migrations_utils:format_migration_name(
Migration
))/binary>>
)
end
).
-file("src/cigogne.gleam", 197).
?DOC(" Apply or roll back the next `count` migrations.\n").
-spec execute_n_migrations(migration_engine(), integer()) -> {ok, nil} |
{error, cigogne@types:migrate_error()}.
execute_n_migrations(Engine, Count) ->
_pipe = cigogne@internal@migrations_utils:find_n_migrations_to_apply(
erlang:element(5, Engine),
erlang:element(4, Engine),
Count
),
gleam@result:'try'(_pipe, fun(Migrations) -> case Count > 0 of
true ->
_pipe@1 = Migrations,
gleam@list:try_each(
_pipe@1,
fun(_capture) -> apply_migration(Engine, _capture) end
);
false ->
_pipe@2 = Migrations,
gleam@list:try_each(
_pipe@2,
fun(_capture@1) ->
roll_back_migration(Engine, _capture@1)
end
)
end end).
-file("src/cigogne.gleam", 260).
?DOC(" Get all defined migrations in your project.\n").
-spec get_migrations(migration_engine()) -> {ok,
list(cigogne@types:migration())} |
{error, cigogne@types:migrate_error()}.
get_migrations(Engine) ->
_pipe = erlang:element(5, Engine),
{ok, _pipe}.
-file("src/cigogne.gleam", 267).
?DOC(" Get details about the schema of the database.\n").
-spec get_schema(migration_engine()) -> {ok, binary()} |
{error, cigogne@types:migrate_error()}.
get_schema(Engine) ->
cigogne@internal@database:get_schema(erlang:element(2, Engine)).
-file("src/cigogne.gleam", 272).
?DOC(" Create or update a schema file if the engine configuration permits it.\n").
-spec update_schema(migration_engine()) -> {ok, nil} |
{error, cigogne@types:migrate_error()}.
update_schema(Engine) ->
case erlang:element(2, erlang:element(3, Engine)) of
false ->
{ok, nil};
true ->
gleam@result:'try'(
get_schema(Engine),
fun(Schema) ->
_pipe = cigogne@internal@fs:write_schema_file(
erlang:element(3, erlang:element(3, Engine)),
Schema
),
gleam@result:map(
_pipe,
fun(_) ->
gleam_stdlib:println(<<"Schema file updated"/utf8>>)
end
)
end
)
end.
-file("src/cigogne.gleam", 315).
?DOC(" Print a MigrateError to the standard error stream.\n").
-spec print_error(cigogne@types:migrate_error()) -> nil.
print_error(Error) ->
cigogne@types:print_migrate_error(Error).
-file("src/cigogne.gleam", 344).
?DOC(" Apply a migration to the database if it hasn't been applied.\n").
-spec apply_migration_if_not_applied(
migration_engine(),
cigogne@types:migration()
) -> {ok, nil} | {error, cigogne@types:migrate_error()}.
apply_migration_if_not_applied(Engine, Migration) ->
gleam@bool:guard(
begin
_pipe = cigogne@internal@migrations_utils:find_migration(
erlang:element(4, Engine),
Migration
),
gleam@result:is_ok(_pipe)
end,
{ok, nil},
fun() -> apply_migration(Engine, Migration) end
).
-file("src/cigogne.gleam", 356).
?DOC(" Checks if a migration is a zero migration (has been created with create_zero_migration)\n").
-spec is_zero_migration(cigogne@types:migration()) -> boolean().
is_zero_migration(Migration) ->
cigogne@internal@migrations_utils:is_zero_migration(Migration).
-file("src/cigogne.gleam", 283).
-spec get_last_applied_migration(migration_engine()) -> {ok,
cigogne@types:migration()} |
{error, cigogne@types:migrate_error()}.
get_last_applied_migration(Engine) ->
_pipe = erlang:element(4, Engine),
_pipe@1 = gleam@list:last(_pipe),
_pipe@2 = gleam@result:replace_error(
_pipe@1,
no_migration_to_rollback_error
),
gleam@result:'try'(
_pipe@2,
fun(Mig) ->
gleam@bool:guard(
is_zero_migration(Mig),
{ok, Mig},
fun() ->
cigogne@internal@migrations_utils:find_migration(
erlang:element(5, Engine),
Mig
)
end
)
end
).
-file("src/cigogne.gleam", 189).
?DOC(" Roll back the last applied migration.\n").
-spec roll_back_previous_migration(migration_engine()) -> {ok, nil} |
{error, cigogne@types:migrate_error()}.
roll_back_previous_migration(Engine) ->
gleam@result:'try'(
get_last_applied_migration(Engine),
fun(Last) -> roll_back_migration(Engine, Last) end
).
-file("src/cigogne.gleam", 295).
-spec show(migration_engine()) -> {ok, nil} |
{error, cigogne@types:migrate_error()}.
show(Engine) ->
gleam@result:'try'(
get_last_applied_migration(Engine),
fun(Last) ->
gleam_stdlib:println(
<<"Last applied migration: "/utf8,
(cigogne@internal@migrations_utils:format_migration_name(
Last
))/binary>>
),
case erlang:element(2, erlang:element(3, Engine)) of
false ->
{ok, nil};
true ->
gleam@result:'try'(
get_schema(Engine),
fun(Schema) ->
gleam_stdlib:println(<<""/utf8>>),
gleam_stdlib:println(Schema),
{ok, nil}
end
)
end
end
).
-file("src/cigogne.gleam", 321).
?DOC(
" Verify the hash integrity of applied migrations.\n"
" If an already applied migration has been modified, it should most likely be run again by the user.\n"
).
-spec verify_applied_migration_hashes(
list(cigogne@types:migration()),
list(cigogne@types:migration())
) -> {ok, nil} | {error, cigogne@types:migrate_error()}.
verify_applied_migration_hashes(Applied, Files) ->
case Applied of
[] ->
{ok, nil};
[Mig | Rest] ->
case is_zero_migration(Mig) of
true ->
verify_applied_migration_hashes(Rest, Files);
false ->
gleam@result:'try'(
cigogne@internal@migrations_utils:find_migration(
Files,
Mig
),
fun(File) ->
case erlang:element(7, Mig) =:= erlang:element(
7,
File
) of
false ->
{error,
{file_hash_changed,
erlang:element(3, Mig),
erlang:element(4, Mig)}};
true ->
verify_applied_migration_hashes(Rest, Files)
end
end
)
end
end.
-file("src/cigogne.gleam", 136).
?DOC(
" Creates a MigrationEngine from a configuration.\n"
" This function will try to connect to the database, create the migrations table if it doesn't exist.\n"
" Then it will fetch the applied migrations and the existing migration files and check hashes do match.\n"
).
-spec create_migration_engine(cigogne@types:config()) -> {ok,
migration_engine()} |
{error, cigogne@types:migrate_error()}.
create_migration_engine(Config) ->
gleam@result:'try'(
cigogne@internal@database:init(
erlang:element(2, Config),
erlang:element(3, Config),
erlang:element(4, Config)
),
fun(Db_data) ->
gleam@result:'try'(
cigogne@internal@database:apply_cigogne_zero(Db_data),
fun(_) ->
gleam@result:'try'(
cigogne@internal@database:get_applied_migrations(
Db_data
),
fun(Applied) ->
gleam@result:'try'(
cigogne@internal@fs:get_migrations(
erlang:element(6, Config),
erlang:element(7, Config)
),
fun(Files) ->
gleam@result:'try'(
verify_applied_migration_hashes(
Applied,
Files
),
fun(_) ->
{ok,
{migration_engine,
Db_data,
{schema_data,
erlang:element(
2,
erlang:element(
5,
Config
)
),
erlang:element(
3,
erlang:element(
5,
Config
)
)},
Applied,
Files}}
end
)
end
)
end
)
end
)
end
).
-file("src/cigogne.gleam", 361).
?DOC(" Create a \"zero\" migration that should be applied before the user's migrations\n").
-spec create_zero_migration(binary(), list(binary()), list(binary())) -> cigogne@types:migration().
create_zero_migration(Name, Queries_up, Queries_down) ->
cigogne@internal@migrations_utils:create_zero_migration(
Name,
Queries_up,
Queries_down
).
-file("src/cigogne.gleam", 62).
-spec cli_to_config(cigogne@internal@cli:config_options()) -> cigogne@types:config().
cli_to_config(Cli_config) ->
Connection = cli_to_connection_config(Cli_config),
Database_schema_to_use = begin
_pipe = erlang:element(8, Cli_config),
gleam@option:unwrap(
_pipe,
erlang:element(
3,
{config,
env_var_config,
<<"public"/utf8>>,
<<"_migrations"/utf8>>,
{schema_config, true, <<"./sql.schema"/utf8>>},
<<"priv/migrations"/utf8>>,
<<"*.sql"/utf8>>}
)
)
end,
Migration_table_name = begin
_pipe@1 = erlang:element(9, Cli_config),
gleam@option:unwrap(
_pipe@1,
erlang:element(
4,
{config,
env_var_config,
<<"public"/utf8>>,
<<"_migrations"/utf8>>,
{schema_config, true, <<"./sql.schema"/utf8>>},
<<"priv/migrations"/utf8>>,
<<"*.sql"/utf8>>}
)
)
end,
Gen_schema = erlang:element(10, Cli_config),
Schema_filename = begin
_pipe@2 = erlang:element(11, Cli_config),
gleam@option:unwrap(
_pipe@2,
erlang:element(
3,
erlang:element(
5,
{config,
env_var_config,
<<"public"/utf8>>,
<<"_migrations"/utf8>>,
{schema_config, true, <<"./sql.schema"/utf8>>},
<<"priv/migrations"/utf8>>,
<<"*.sql"/utf8>>}
)
)
)
end,
Schema_config = {schema_config, Gen_schema, Schema_filename},
Migration_folder = begin
_pipe@3 = erlang:element(12, Cli_config),
gleam@option:unwrap(
_pipe@3,
erlang:element(
6,
{config,
env_var_config,
<<"public"/utf8>>,
<<"_migrations"/utf8>>,
{schema_config, true, <<"./sql.schema"/utf8>>},
<<"priv/migrations"/utf8>>,
<<"*.sql"/utf8>>}
)
)
end,
Migration_file_pattern = begin
_pipe@4 = erlang:element(13, Cli_config),
gleam@option:unwrap(
_pipe@4,
erlang:element(
7,
{config,
env_var_config,
<<"public"/utf8>>,
<<"_migrations"/utf8>>,
{schema_config, true, <<"./sql.schema"/utf8>>},
<<"priv/migrations"/utf8>>,
<<"*.sql"/utf8>>}
)
)
end,
{config,
Connection,
Database_schema_to_use,
Migration_table_name,
Schema_config,
Migration_folder,
Migration_file_pattern}.
-file("src/cigogne.gleam", 31).
-spec main() -> {ok, nil} | {error, nil}.
main() ->
Args = erlang:element(4, argv:load()),
gleam@result:'try'(
cigogne@internal@cli:get_action(Args),
fun(Cli_action) -> _pipe@9 = case Cli_action of
{new_migration, Folder, Name} ->
new_migration(
begin
_pipe = Folder,
gleam@option:unwrap(
_pipe,
erlang:element(
6,
{config,
env_var_config,
<<"public"/utf8>>,
<<"_migrations"/utf8>>,
{schema_config,
true,
<<"./sql.schema"/utf8>>},
<<"priv/migrations"/utf8>>,
<<"*.sql"/utf8>>}
)
)
end,
Name
);
{show_migrations, Options} ->
_pipe@1 = cli_to_config(Options),
_pipe@2 = create_migration_engine(_pipe@1),
gleam@result:'try'(_pipe@2, fun show/1);
{migrate_up, Options@1, Count} ->
_pipe@3 = cli_to_config(Options@1),
_pipe@4 = create_migration_engine(_pipe@3),
gleam@result:'try'(
_pipe@4,
fun(_capture) ->
execute_n_migrations(_capture, Count)
end
);
{migrate_down, Options@2, Count@1} ->
_pipe@5 = cli_to_config(Options@2),
_pipe@6 = create_migration_engine(_pipe@5),
gleam@result:'try'(
_pipe@6,
fun(_capture@1) ->
execute_n_migrations(_capture@1, - Count@1)
end
);
{migrate_to_last, Options@3} ->
_pipe@7 = cli_to_config(Options@3),
_pipe@8 = create_migration_engine(_pipe@7),
gleam@result:'try'(
_pipe@8,
fun execute_migrations_to_last/1
)
end,
gleam@result:map_error(
_pipe@9,
fun cigogne@types:print_migrate_error/1
) end
).