-module(cigogne). -compile([no_auto_import, nowarn_unused_vars, nowarn_unused_function, nowarn_nomatch]). -define(FILEPATH, "src/cigogne.gleam"). -export([read_migrations/1, create_engine/1, new_migration/2, update_config/1, include_lib/2, remove_lib/2, apply_migrations/2, apply/1, apply_n/2, apply_all/1, rollback_migrations/2, rollback/1, rollback_n/2, get_all_migrations/1, get_applied_migrations/1, get_unapplied_migrations/1, print_error/1, main/0, apply_migration_if_not_applied/2]). -export_type([migration_engine/0, cigogne_error/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. -opaque migration_engine() :: {migration_engine, cigogne@internal@database:database_data(), list(cigogne@migration:migration()), list(cigogne@migration:migration()), list(cigogne@migration:migration()), cigogne@config:config()}. -type cigogne_error() :: {database_error, cigogne@internal@database:database_error()} | {f_s_error, cigogne@internal@fs:f_s_error()} | {migration_error, cigogne@migration:migration_error()} | {parser_error, cigogne@internal@parser_formatter:parser_error()} | {config_error, cigogne@config:config_error()} | nothing_to_rollback | nothing_to_apply | {lib_not_included, binary()} | {compound_error, list(cigogne_error())}. -file("src/cigogne.gleam", 165). -spec warn_no_hash_check(cigogne@config:config()) -> nil. warn_no_hash_check(Config) -> case erlang:element(5, erlang:element(4, Config)) of {some, true} -> gleam_stdlib:println( <<"Warning: no_hash_check is enabled ! Do not use it in production environments as it can lead to inconsistencies between your migration files and the database."/utf8>> ); _ -> nil end. -file("src/cigogne.gleam", 175). -spec init_db_and_get_applied(cigogne@config:config()) -> {ok, {cigogne@internal@database:database_data(), list(cigogne@migration:migration())}} | {error, cigogne_error()}. init_db_and_get_applied(Config) -> _pipe = begin gleam@result:'try'( cigogne@internal@database:init(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) -> {ok, {Db_data, Applied}} end ) end ) end ) end, gleam@result:map_error(_pipe, fun(Field@0) -> {database_error, Field@0} end). -file("src/cigogne.gleam", 192). ?DOC( " Read all migration files from the folder specified in the configuration .\n" " It is recommended to use `create_engine` and `get_all_migrations` instead of this function.\n" " It can still be useful if you want to read migrations without connecting to the database.\n" ). -spec read_migrations(cigogne@config:config()) -> {ok, list(cigogne@migration:migration())} | {error, cigogne_error()}. read_migrations(Config) -> Files = begin _pipe = begin gleam@result:'try'( cigogne@internal@fs:priv( erlang:element(2, erlang:element(4, Config)) ), fun(Priv) -> cigogne@internal@fs:read_directory( <<<>/binary, (cigogne@config:get_migrations_folder( erlang:element(4, Config) ))/binary>> ) end ) end, gleam@result:map_error(_pipe, fun(Field@0) -> {f_s_error, Field@0} end) end, gleam@result:'try'( Files, fun(Files@1) -> Results = gleam@list:map( Files@1, fun(File) -> _pipe@1 = cigogne@internal@parser_formatter:parse(File), gleam@result:map_error( _pipe@1, fun(Field@0) -> {parser_error, Field@0} end ) end ), _pipe@2 = cigogne@internal@utils:get_results_or_errors(Results), gleam@result:map_error( _pipe@2, fun(Field@0) -> {compound_error, Field@0} end ) end ). -file("src/cigogne.gleam", 145). ?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" " \n" " Example usage:\n" " ```gleam\n" " import cigogne/config\n" " import cigogne/cigogne\n" " \n" " pub fn main() {\n" " use app_name <- result.try(config.get_app_name())\n" " use config <- result.try(config.get(app_name))\n" " use engine <- result.try(cigogne.create_engine(config))\n" " \n" " // Now you can use the engine to apply or rollback migrations\n" " use _ <- result.try(cigogne.apply(engine))\n" " use _ <- result.try(cigogne.rollback(engine))\n" "\n" " // Rest of your application logic\n" " }\n" " ```\n" ). -spec create_engine(cigogne@config:config()) -> {ok, migration_engine()} | {error, cigogne_error()}. create_engine(Config) -> warn_no_hash_check(Config), gleam@result:'try'( init_db_and_get_applied(Config), fun(_use0) -> {Db_data, Applied} = _use0, gleam@result:'try'( read_migrations(Config), fun(Files) -> gleam@result:'try'( begin _pipe@1 = cigogne@migration:match_migrations( Applied, Files, begin _pipe = erlang:element( 5, erlang:element(4, Config) ), gleam@option:unwrap(_pipe, false) end ), gleam@result:map_error( _pipe@1, fun(Field@0) -> {migration_error, Field@0} end ) end, fun(Applied@1) -> Unapplied = cigogne@migration:find_unapplied( Files, Applied@1 ), {ok, {migration_engine, Db_data, Files, Applied@1, Unapplied, Config}} end ) end ) end ). -file("src/cigogne.gleam", 217). ?DOC( " Create a new migration file in the folder specified by the configuration with the provided name.\n" " Note: Migrations are always created in the `priv/` folder.\n" ). -spec new_migration(cigogne@config:migrations_config(), binary()) -> {ok, nil} | {error, cigogne_error()}. new_migration(Migrations_config, Name) -> gleam@result:'try'( begin _pipe = cigogne@migration:new( <<"priv/"/utf8, (cigogne@config:get_migrations_folder(Migrations_config))/binary>>, Name, gleam@time@timestamp:system_time() ), gleam@result:map_error( _pipe, fun(Field@0) -> {migration_error, Field@0} end ) end, fun(New_mig) -> _pipe@1 = New_mig, _pipe@2 = cigogne@internal@parser_formatter:format(_pipe@1), _pipe@3 = cigogne@internal@fs:write_file(_pipe@2), _pipe@4 = gleam@result:map_error( _pipe@3, fun(Field@0) -> {f_s_error, Field@0} end ), gleam@result:map( _pipe@4, fun(_) -> gleam_stdlib:println( <<"Migration file created : "/utf8, (erlang:element(2, New_mig))/binary>> ) end ) end ). -file("src/cigogne.gleam", 242). ?DOC( " Update the configuration file at `priv/cigogne.toml` with the provided configuration.\n" " If the file doesn't exist, it will be created.\n" " If it already exists, it will be overwritten.\n" ). -spec update_config(cigogne@config:config()) -> {ok, nil} | {error, cigogne_error()}. update_config(Config) -> gleam@result:map( begin _pipe = cigogne@config:write(Config), gleam@result:map_error( _pipe, fun(Field@0) -> {config_error, Field@0} end ) end, fun(_) -> gleam_stdlib:println( <<"Updated config file at priv/cigogne.toml"/utf8>> ) end ). -file("src/cigogne.gleam", 340). ?DOC( " Include a library's migrations into your project.\n" " This will create a new migration that applies all migrations from the library that haven't been applied yet.\n" " This will fail if you haven't added the library to your project.\n" "\n" " Example usage:\n" " ```sh\n" " gleam add my_lib\n" " gleam run -m cigogne include --lib-name my_lib\n" " # There will be a new migration file created in priv/migrations with name `-my_lib`\n" " ```\n" ). -spec include_lib(migration_engine(), binary()) -> {ok, nil} | {error, cigogne_error()}. include_lib(Migration_engine, Lib_name) -> gleam@result:'try'( begin _pipe = cigogne@config:get(Lib_name), gleam@result:map_error( _pipe, fun(Field@0) -> {config_error, Field@0} end ) end, fun(Lib_config) -> gleam@result:'try'( read_migrations(Lib_config), fun(Lib_migrations) -> Last_migration_for_dep = begin _pipe@1 = erlang:element( 4, erlang:element( 4, erlang:element(6, Migration_engine) ) ), gleam@list:key_find(_pipe@1, Lib_name) end, Lib_migrations@1 = case Last_migration_for_dep of {error, _} -> Lib_migrations; {ok, Name} -> _pipe@2 = Lib_migrations, _pipe@3 = gleam@list:drop_while( _pipe@2, fun(Mig) -> cigogne@migration:to_fullname(Mig) /= Name end ), gleam@list:drop(_pipe@3, 1) end, gleam@result:'try'( begin _pipe@4 = cigogne@migration:merge( Lib_migrations@1, gleam@time@timestamp:system_time(), Lib_name ), gleam@result:map_error( _pipe@4, fun(Field@0) -> {migration_error, Field@0} end ) end, fun(Merged_mig) -> Merged_mig@1 = begin _pipe@5 = Merged_mig, cigogne@migration:set_folder( _pipe@5, <<"priv/"/utf8, (cigogne@config:get_migrations_folder( erlang:element( 4, erlang:element( 6, Migration_engine ) ) ))/binary>> ) end, New_file = cigogne@internal@parser_formatter:format( Merged_mig@1 ), gleam@result:'try'( begin _pipe@6 = New_file, _pipe@7 = cigogne@internal@fs:write_file( _pipe@6 ), gleam@result:map_error( _pipe@7, fun(Field@0) -> {f_s_error, Field@0} end ) end, fun(_) -> gleam_stdlib:println( <<"Created migration at "/utf8, (erlang:element(2, New_file))/binary>> ), Last_migration@1 = case gleam@list:last( Lib_migrations@1 ) of {ok, Last_migration} -> Last_migration; _assert_fail -> erlang:error( #{gleam_error => let_assert, message => <<"Pattern match failed, no pattern matched the value."/utf8>>, file => <>, module => <<"cigogne"/utf8>>, function => <<"include_lib"/utf8>>, line => 378, value => _assert_fail, start => 12126, 'end' => 12183, pattern_start => 12137, pattern_end => 12155} ) end, New_config = begin _record = erlang:element( 6, Migration_engine ), {config, erlang:element(2, _record), erlang:element(3, _record), begin _record@1 = erlang:element( 4, erlang:element( 6, Migration_engine ) ), {migrations_config, erlang:element(2, _record@1), erlang:element(3, _record@1), begin _pipe@8 = erlang:element( 4, erlang:element( 4, erlang:element( 6, Migration_engine ) ) ), gleam@list:key_set( _pipe@8, Lib_name, begin _pipe@9 = Last_migration@1, cigogne@migration:to_fullname( _pipe@9 ) end ) end, erlang:element(5, _record@1)} end} end, _pipe@10 = cigogne@config:write(New_config), gleam@result:map_error( _pipe@10, fun(Field@0) -> {config_error, Field@0} end ) end ) end ) end ) end ). -file("src/cigogne.gleam", 406). ?DOC( " Remove a library's migrations from your project.\n" " This will create a new migration that applies all the down migrations from the migrations created by include for this library.\n" " This will fail if you haven't included the library yet.\n" "\n" " Example usage:\n" " ```sh\n" " gleam add my_lib\n" " gleam run -m cigogne include --lib-name my_lib\n" " gleam run -m cigogne remove --lib-name my_lib\n" " # There will be a new migration file created in priv/migrations with name `-remove_my_lib`\n" " ```\n" ). -spec remove_lib(migration_engine(), binary()) -> {ok, nil} | {error, cigogne_error()}. remove_lib(Migration_engine, Lib_name) -> Opposite_migrations = begin _pipe = erlang:element(3, Migration_engine), _pipe@1 = gleam@list:filter( _pipe, fun(Mig) -> erlang:element(4, Mig) =:= Lib_name end ), _pipe@2 = gleam@list:map(_pipe@1, fun(Mig@1) -> _record = Mig@1, {migration, erlang:element(2, _record), erlang:element(3, _record), erlang:element(4, _record), erlang:element(6, Mig@1), erlang:element(5, Mig@1), erlang:element(7, _record)} end), lists:reverse(_pipe@2) end, gleam@bool:guard( gleam@list:is_empty(Opposite_migrations), {error, {lib_not_included, Lib_name}}, fun() -> gleam@result:'try'( begin _pipe@3 = cigogne@migration:merge( Opposite_migrations, gleam@time@timestamp:system_time(), <<"remove_"/utf8, Lib_name/binary>> ), gleam@result:map_error( _pipe@3, fun(Field@0) -> {migration_error, Field@0} end ) end, fun(Merged_mig) -> Merged_mig@1 = begin _pipe@4 = Merged_mig, cigogne@migration:set_folder( _pipe@4, <<"priv/"/utf8, (cigogne@config:get_migrations_folder( erlang:element( 4, erlang:element(6, Migration_engine) ) ))/binary>> ) end, New_file = cigogne@internal@parser_formatter:format( Merged_mig@1 ), gleam@result:'try'( begin _pipe@5 = New_file, _pipe@6 = cigogne@internal@fs:write_file(_pipe@5), gleam@result:map_error( _pipe@6, fun(Field@0) -> {f_s_error, Field@0} end ) end, fun(_) -> gleam_stdlib:println( <<"Created migration at "/utf8, (erlang:element(2, New_file))/binary>> ), New_config = begin _record@1 = erlang:element(6, Migration_engine), {config, erlang:element(2, _record@1), erlang:element(3, _record@1), begin _record@2 = erlang:element( 4, erlang:element(6, Migration_engine) ), {migrations_config, erlang:element(2, _record@2), erlang:element(3, _record@2), begin _pipe@7 = erlang:element( 4, erlang:element( 4, erlang:element( 6, Migration_engine ) ) ), gleam@list:filter( _pipe@7, fun(Dep) -> erlang:element(1, Dep) /= Lib_name end ) end, erlang:element(5, _record@2)} end} end, _pipe@8 = cigogne@config:write(New_config), gleam@result:map_error( _pipe@8, fun(Field@0) -> {config_error, Field@0} end ) end ) end ) end ). -file("src/cigogne.gleam", 471). ?DOC( " Apply migrations to the database.\n" " It is recommended to use `apply` or `apply_n` instead of this function directly.\n" " It can still be useful if you want to apply specific migrations or zero migrations.\n" " All migrations will be applied in a single transaction, so either all are applied or none is.\n" "\n" " Be careful though as we don't check if the migration has already been applied or not, see `apply_migration_if_not_applied` for this use case.\n" ). -spec apply_migrations(migration_engine(), list(cigogne@migration:migration())) -> {ok, nil} | {error, cigogne_error()}. apply_migrations(Engine, Migrations) -> _pipe = begin cigogne@internal@database:transaction( erlang:element(2, Engine), fun(Transaction) -> Db_data = begin _record = erlang:element(2, Engine), {database_data, Transaction, erlang:element(3, _record), erlang:element(4, _record)} end, gleam@list:try_each( Migrations, fun(Migration) -> gleam_stdlib:println( <<"\nApplying migration "/utf8, (cigogne@migration:to_fullname(Migration))/binary>> ), cigogne@internal@database:apply_migration_no_transaction( Db_data, Migration ) end ) end ) end, _pipe@1 = gleam@result:map_error( _pipe, fun(Field@0) -> {database_error, Field@0} end ), gleam@result:map( _pipe@1, fun(_) -> gleam_stdlib:println( <<"Migrations applied:\n\t"/utf8, (begin _pipe@2 = gleam@list:map( Migrations, fun cigogne@migration:to_fullname/1 ), gleam@string:join(_pipe@2, <<"\n\t"/utf8>>) end)/binary>> ) end ). -file("src/cigogne.gleam", 250). ?DOC( " Apply the next migration that wasn't applied yet.\n" " See `create_engine` for an example usage.\n" " See `apply_n` to apply multiple migrations at once.\n" ). -spec apply(migration_engine()) -> {ok, nil} | {error, cigogne_error()}. apply(Engine) -> _pipe = erlang:element(5, Engine), _pipe@1 = gleam@list:first(_pipe), _pipe@2 = gleam@result:replace_error(_pipe@1, nothing_to_apply), gleam@result:'try'(_pipe@2, fun(Mig) -> apply_migrations(Engine, [Mig]) end). -file("src/cigogne.gleam", 278). ?DOC( " Apply the next `count` migrations.\n" " If `count` is less than or equal to 0, this function does nothing.\n" " If there is no migration to apply, it returns an error.\n" " If there are less than `count` migrations to apply, it applies all of them.\n" " \n" " Example usage:\n" " ```gleam\n" " use engine <- result.try(cigogne.create_engine(config))\n" " use _ <- result.try(cigogne.apply_n(engine, 3)) // Apply the next 3 migrations\n" " ```\n" ). -spec apply_n(migration_engine(), integer()) -> {ok, nil} | {error, cigogne_error()}. apply_n(Engine, Count) -> gleam@bool:guard( Count =< 0, {ok, nil}, fun() -> Migrations_to_apply = begin _pipe = erlang:element(5, Engine), gleam@list:take(_pipe, Count) end, case Migrations_to_apply of [] -> {error, nothing_to_apply}; _ -> apply_migrations(Engine, Migrations_to_apply) end end ). -file("src/cigogne.gleam", 326). ?DOC( " Apply all unapplied migrations.\n" "\n" " Example usage:\n" " ```gleam\n" " use engine <- result.try(cigogne.create_engine(config))\n" " use _ <- result.try(cigogne.apply_all(engine))\n" " ```\n" ). -spec apply_all(migration_engine()) -> {ok, nil} | {error, cigogne_error()}. apply_all(Engine) -> apply_migrations(Engine, erlang:element(5, Engine)). -file("src/cigogne.gleam", 499). ?DOC( " Roll back migrations from the database.\n" " It is recommended to use `rollback` or `rollback_n` instead of this function directly.\n" " It can still be useful if you want to roll back specific migrations or a zero migrations.\n" " All migrations will be rolled back in a single transaction, so either all are rolled back or none is.\n" "\n" " Be careful though as we don't check if the migration has been applied or not.\n" ). -spec rollback_migrations( migration_engine(), list(cigogne@migration:migration()) ) -> {ok, nil} | {error, cigogne_error()}. rollback_migrations(Engine, Migrations) -> _pipe = begin cigogne@internal@database:transaction( erlang:element(2, Engine), fun(Transaction) -> Db_data = begin _record = erlang:element(2, Engine), {database_data, Transaction, erlang:element(3, _record), erlang:element(4, _record)} end, gleam@list:try_each( Migrations, fun(Migration) -> gleam_stdlib:println( <<"\nRolling back migration "/utf8, (cigogne@migration:to_fullname(Migration))/binary>> ), cigogne@internal@database:rollback_migration_no_transaction( Db_data, Migration ) end ) end ) end, _pipe@1 = gleam@result:map_error( _pipe, fun(Field@0) -> {database_error, Field@0} end ), gleam@result:map( _pipe@1, fun(_) -> gleam_stdlib:println( <<"Migrations rolled back:\n\t"/utf8, (begin _pipe@2 = gleam@list:map( Migrations, fun cigogne@migration:to_fullname/1 ), gleam@string:join(_pipe@2, <<"\n\t"/utf8>>) end)/binary>> ) end ). -file("src/cigogne.gleam", 260). ?DOC( " Roll back the last applied migration.\n" " See `create_engine` for an example usage.\n" " See `rollback_n` to rollback multiple migrations at once.\n" ). -spec rollback(migration_engine()) -> {ok, nil} | {error, cigogne_error()}. rollback(Engine) -> _pipe = erlang:element(4, Engine), _pipe@1 = gleam@list:drop_while( _pipe, fun cigogne@migration:is_zero_migration/1 ), _pipe@2 = gleam@list:last(_pipe@1), _pipe@3 = gleam@result:replace_error(_pipe@2, nothing_to_rollback), gleam@result:'try'( _pipe@3, fun(Mig) -> rollback_migrations(Engine, [Mig]) end ). -file("src/cigogne.gleam", 301). ?DOC( " Roll back `count` migrations.\n" " If `count` is less than or equal to 0, this function does nothing.\n" " If there is no migration to rollback, it returns an error.\n" " If there are less than `count` migrations to rollback, it rolls all of them back.\n" " \n" " Example usage:\n" " ```gleam\n" " use engine <- result.try(cigogne.create_engine(config))\n" " use _ <- result.try(cigogne.rollback_n(engine, 3)) // Rollback the next 3 migrations\n" " ```\n" ). -spec rollback_n(migration_engine(), integer()) -> {ok, nil} | {error, cigogne_error()}. rollback_n(Engine, Count) -> gleam@bool:guard( Count =< 0, {ok, nil}, fun() -> Migrations_to_rollback = begin _pipe = erlang:element(4, Engine), _pipe@1 = gleam@list:drop_while( _pipe, fun cigogne@migration:is_zero_migration/1 ), _pipe@2 = lists:reverse(_pipe@1), gleam@list:take(_pipe@2, Count) end, case Migrations_to_rollback of [] -> {error, nothing_to_rollback}; _ -> rollback_migrations(Engine, Migrations_to_rollback) end end ). -file("src/cigogne.gleam", 522). ?DOC(" Get all defined migrations in your project.\n"). -spec get_all_migrations(migration_engine()) -> list(cigogne@migration:migration()). get_all_migrations(Engine) -> erlang:element(3, Engine). -file("src/cigogne.gleam", 527). ?DOC(" Get applied migrations in your project.\n"). -spec get_applied_migrations(migration_engine()) -> list(cigogne@migration:migration()). get_applied_migrations(Engine) -> erlang:element(4, Engine). -file("src/cigogne.gleam", 534). ?DOC(" Get unapplied migrations in your project.\n"). -spec get_unapplied_migrations(migration_engine()) -> list(cigogne@migration:migration()). get_unapplied_migrations(Engine) -> erlang:element(5, Engine). -file("src/cigogne.gleam", 540). -spec show(migration_engine()) -> nil. show(Engine) -> Migration_names = begin _pipe = erlang:element(4, Engine), gleam@list:map(_pipe, fun cigogne@migration:to_fullname/1) end, To_apply = begin _pipe@1 = erlang:element(5, Engine), gleam@list:map(_pipe@1, fun cigogne@migration:to_fullname/1) end, gleam_stdlib:println( <<<<"Applied migrations: \n - "/utf8, (begin _pipe@2 = Migration_names, gleam@string:join(_pipe@2, <<"\n - "/utf8>>) end)/binary>>/binary, "\n"/utf8>> ), gleam_stdlib:println( <<"Migrations to apply: \n - "/utf8, (begin _pipe@3 = To_apply, gleam@string:join(_pipe@3, <<"\n - "/utf8>>) end)/binary>> ). -file("src/cigogne.gleam", 552). -spec print_unapplied(migration_engine()) -> nil. print_unapplied(Migration_engine) -> gleam_stdlib:print(<<"Unapplied migrations:"/utf8>>), gleam@list:each( erlang:element(5, Migration_engine), fun(Unapplied_mig) -> gleam_stdlib:println( <<<<"\n\n--- == "/utf8, (cigogne@migration:to_fullname(Unapplied_mig))/binary>>/binary, " ==\n"/utf8>> ), gleam_stdlib:println( begin _pipe = erlang:element(5, Unapplied_mig), gleam@string:join(_pipe, <<"\n"/utf8>>) end ) end ). -file("src/cigogne.gleam", 566). -spec get_error_message(cigogne_error()) -> binary(). get_error_message(Error) -> case Error of {compound_error, Errors} -> <<"Many errors happened ! Here is the list:\n "/utf8, (begin _pipe = Errors, _pipe@1 = gleam@list:map(_pipe, fun get_error_message/1), gleam@string:join(_pipe@1, <<"\n "/utf8>>) end)/binary>>; {config_error, Error@1} -> <<"Configuration error: "/utf8, (cigogne@config:get_error_message(Error@1))/binary>>; {database_error, Error@2} -> <<"Database error: "/utf8, (cigogne@internal@database:get_error_message(Error@2))/binary>>; {f_s_error, Error@3} -> <<"FS error: "/utf8, (cigogne@internal@fs:get_error_message(Error@3))/binary>>; {lib_not_included, Name} -> <<<<"There were no migrations for library "/utf8, Name/binary>>/binary, " ! Did you include it ?"/utf8>>; {migration_error, Error@4} -> <<"Migration error: "/utf8, (cigogne@migration:get_error_message(Error@4))/binary>>; nothing_to_apply -> <<"There is no migration to apply ! You are up-to-date !"/utf8>>; nothing_to_rollback -> <<"There is no migration to rollback !"/utf8>>; {parser_error, Error@5} -> <<"Parser error: "/utf8, (cigogne@internal@parser_formatter:get_error_message(Error@5))/binary>> end. -file("src/cigogne.gleam", 562). ?DOC(" Print a MigrateError to the standard error stream.\n"). -spec print_error(cigogne_error()) -> nil. print_error(Error) -> gleam_stdlib:println_error(get_error_message(Error)). -file("src/cigogne.gleam", 69). ?DOC( " The main entry point of the Cigogne CLI.\n" " \n" " Example usage:\n" " ```sh\n" " # List all possible actions\n" " gleam run -m cigogne help\n" " # Create a new migration\n" " gleam run -m cigogne new --name AddUsers\n" " # Apply a single migration\n" " gleam run -m cigogne up\n" " # Apply the next 3 migrations\n" " gleam run -m cigogne up --count 3\n" " # Apply all unapplied migrations\n" " gleam run -m cigogne all\n" " # Rollback a single migration\n" " gleam run -m cigogne down\n" " ```\n" ). -spec main() -> {ok, nil} | {error, nil}. main() -> Args = erlang:element(4, argv:load()), Application_name@1 = case cigogne@config:get_app_name() of {ok, Application_name} -> Application_name; _assert_fail -> erlang:error(#{gleam_error => let_assert, message => <<"Pattern match failed, no pattern matched the value."/utf8>>, file => <>, module => <<"cigogne"/utf8>>, function => <<"main"/utf8>>, line => 71, value => _assert_fail, start => 2154, 'end' => 2209, pattern_start => 2165, pattern_end => 2185}) end, Cigogne_config@1 = case cigogne@config:get(Application_name@1) of {ok, Cigogne_config} -> Cigogne_config; _assert_fail@1 -> erlang:error(#{gleam_error => let_assert, message => <<"Pattern match failed, no pattern matched the value."/utf8>>, file => <>, module => <<"cigogne"/utf8>>, function => <<"main"/utf8>>, line => 72, value => _assert_fail@1, start => 2212, 'end' => 2272, pattern_start => 2223, pattern_end => 2241}) end, gleam@result:'try'( cigogne@internal@cli:get_action(Application_name@1, Args), fun(Cli_action) -> _pipe@26 = case Cli_action of {new_migration, Migrations, Name} -> _pipe = erlang:element(4, Cigogne_config@1), _pipe@1 = cigogne@config:merge_migrations_config( _pipe, Migrations ), new_migration(_pipe@1, Name); {show_migrations, Config} -> _pipe@2 = Cigogne_config@1, _pipe@3 = cigogne@config:merge(_pipe@2, Config), _pipe@4 = create_engine(_pipe@3), gleam@result:map(_pipe@4, fun show/1); {migrate_up, Config@1, Count} -> _pipe@5 = Cigogne_config@1, _pipe@6 = cigogne@config:merge(_pipe@5, Config@1), _pipe@7 = create_engine(_pipe@6), gleam@result:'try'( _pipe@7, fun(_capture) -> apply_n(_capture, Count) end ); {migrate_down, Config@2, Count@1} -> _pipe@8 = Cigogne_config@1, _pipe@9 = cigogne@config:merge(_pipe@8, Config@2), _pipe@10 = create_engine(_pipe@9), gleam@result:'try'( _pipe@10, fun(_capture@1) -> rollback_n(_capture@1, Count@1) end ); {migrate_up_all, Config@3} -> _pipe@11 = Cigogne_config@1, _pipe@12 = cigogne@config:merge(_pipe@11, Config@3), _pipe@13 = create_engine(_pipe@12), gleam@result:'try'(_pipe@13, fun apply_all/1); {include_lib, Config@4, Lib_name} -> _pipe@14 = Cigogne_config@1, _pipe@15 = cigogne@config:merge(_pipe@14, Config@4), _pipe@16 = create_engine(_pipe@15), gleam@result:'try'( _pipe@16, fun(_capture@2) -> include_lib(_capture@2, Lib_name) end ); {remove_lib, Config@5, Lib_name@1} -> _pipe@17 = Cigogne_config@1, _pipe@18 = cigogne@config:merge(_pipe@17, Config@5), _pipe@19 = create_engine(_pipe@18), gleam@result:'try'( _pipe@19, fun(_capture@3) -> remove_lib(_capture@3, Lib_name@1) end ); {update_config, Config@6} -> _pipe@20 = Cigogne_config@1, _pipe@21 = cigogne@config:merge(_pipe@20, Config@6), update_config(_pipe@21); init_config -> _pipe@22 = Cigogne_config@1, update_config(_pipe@22); {print_unapplied, Config@7} -> _pipe@23 = Cigogne_config@1, _pipe@24 = cigogne@config:merge(_pipe@23, Config@7), _pipe@25 = create_engine(_pipe@24), gleam@result:map(_pipe@25, fun print_unapplied/1) end, gleam@result:map_error(_pipe@26, fun print_error/1) end ). -file("src/cigogne.gleam", 590). ?DOC(" Apply a migration to the database if it hasn't been applied.\n"). -spec apply_migration_if_not_applied( migration_engine(), cigogne@migration:migration() ) -> {ok, nil} | {error, cigogne_error()}. apply_migration_if_not_applied(Engine, Migration) -> case cigogne@internal@utils:find_compare( erlang:element(4, Engine), Migration, fun cigogne@migration:compare/2 ) of {ok, _} -> {ok, nil}; {error, _} -> apply_migrations(Engine, [Migration]) end.