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/1, apply_n/2, apply_to_last/1, rollback_migration/2, rollback_n/2, get_migrations/1, get_schema/1, update_schema/1, print_error/1, apply_migration_if_not_applied/2, is_zero_migration/1, rollback/1, create_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", 92).
-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 ->
case {erlang:element(4, Cli_config),
erlang:element(5, Cli_config),
erlang:element(3, Cli_config),
erlang:element(6, Cli_config),
erlang:element(7, Cli_config)} of
{none, none, none, none, none} ->
env_var_config;
{_, _, _, _, _} ->
User = begin
_pipe = erlang:element(4, Cli_config),
gleam@option:unwrap(_pipe, <<"postgres"/utf8>>)
end,
Password = erlang:element(5, Cli_config),
Host = begin
_pipe@1 = erlang:element(3, Cli_config),
gleam@option:unwrap(_pipe@1, <<"localhost"/utf8>>)
end,
Port = begin
_pipe@2 = erlang:element(6, Cli_config),
gleam@option:unwrap(_pipe@2, 5432)
end,
Db_name = begin
_pipe@3 = erlang:element(7, Cli_config),
gleam@option:unwrap(_pipe@3, <<"postgres"/utf8>>)
end,
Procname = gleam_erlang_ffi:new_name(<<"cigogne-db"/utf8>>),
Config = begin
_pipe@4 = pog:default_config(Procname),
_pipe@5 = pog:user(_pipe@4, User),
_pipe@6 = pog:password(_pipe@5, Password),
_pipe@7 = pog:host(_pipe@6, Host),
_pipe@8 = pog:port(_pipe@7, Port),
pog:database(_pipe@8, Db_name)
end,
{pog_config, Config}
end
end.
-file("src/cigogne.gleam", 175).
?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", 243).
?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", 188).
?DOC(" Apply the next migration that wasn't applied yet.\n").
-spec apply(migration_engine()) -> {ok, nil} |
{error, cigogne@types:migrate_error()}.
apply(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", 203).
?DOC(" Apply the next `count` migrations.\n").
-spec apply_n(migration_engine(), integer()) -> {ok, nil} |
{error, cigogne@types:migrate_error()}.
apply_n(Engine, Count) ->
gleam@bool:guard(
Count =< 0,
{ok, nil},
fun() ->
_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) -> _pipe@1 = Migrations,
gleam@list:try_each(
_pipe@1,
fun(_capture) -> apply_migration(Engine, _capture) end
) end)
end
).
-file("src/cigogne.gleam", 237).
?DOC(" Apply migrations until we reach the last defined migration.\n").
-spec apply_to_last(migration_engine()) -> {ok, nil} |
{error, cigogne@types:migrate_error()}.
apply_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", 261).
?DOC(" Roll back a migration from the database.\n").
-spec rollback_migration(migration_engine(), cigogne@types:migration()) -> {ok,
nil} |
{error, cigogne@types:migrate_error()}.
rollback_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", 220).
?DOC(" Roll back `count` migrations.\n").
-spec rollback_n(migration_engine(), integer()) -> {ok, nil} |
{error, cigogne@types:migrate_error()}.
rollback_n(Engine, Count) ->
gleam@bool:guard(
Count =< 0,
{ok, nil},
fun() ->
_pipe = cigogne@internal@migrations_utils:find_n_migrations_to_rollback(
erlang:element(5, Engine),
erlang:element(4, Engine),
Count
),
gleam@result:'try'(_pipe, fun(Migrations) -> _pipe@1 = Migrations,
gleam@list:try_each(
_pipe@1,
fun(_capture) ->
rollback_migration(Engine, _capture)
end
) end)
end
).
-file("src/cigogne.gleam", 280).
?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", 287).
?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", 292).
?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", 335).
?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", 364).
?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", 376).
?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", 303).
-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", 197).
?DOC(" Roll back the last applied migration.\n").
-spec rollback(migration_engine()) -> {ok, nil} |
{error, cigogne@types:migrate_error()}.
rollback(Engine) ->
gleam@result:'try'(
get_last_applied_migration(Engine),
fun(Last) -> rollback_migration(Engine, Last) end
).
-file("src/cigogne.gleam", 315).
-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", 341).
?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", 146).
?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 that hashes do match.\n"
).
-spec create_engine(cigogne@types:config()) -> {ok, migration_engine()} |
{error, cigogne@types:migrate_error()}.
create_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", 381).
?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", 63).
-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", 32).
-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_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_engine(_pipe@3),
gleam@result:'try'(
_pipe@4,
fun(_capture) -> apply_n(_capture, Count) end
);
{migrate_down, Options@2, Count@1} ->
_pipe@5 = cli_to_config(Options@2),
_pipe@6 = create_engine(_pipe@5),
gleam@result:'try'(
_pipe@6,
fun(_capture@1) -> rollback_n(_capture@1, Count@1) end
);
{migrate_to_last, Options@3} ->
_pipe@7 = cli_to_config(Options@3),
_pipe@8 = create_engine(_pipe@7),
gleam@result:'try'(_pipe@8, fun apply_to_last/1)
end,
gleam@result:map_error(
_pipe@9,
fun cigogne@types:print_migrate_error/1
) end
).