-module(galchemy@schema@migration@postgres). -compile([no_auto_import, nowarn_unused_vars, nowarn_unused_function, nowarn_nomatch, inline]). -define(FILEPATH, "src\\galchemy\\schema\\migration\\postgres.gleam"). -export([plan/3, statuses/2, ensure_history_table_query/0, history_query/0, applied_migration_query/1, record_migration_query/1, apply/2]). -export_type([migration_plan/0, applied_migration/0, migration_status/0, apply_error/0]). -type migration_plan() :: {migration_plan, binary(), list(galchemy@schema@diff:schema_operation()), list(binary())}. -type applied_migration() :: {applied_migration, binary(), binary(), integer()}. -type migration_status() :: {pending, migration_plan()} | {applied, migration_plan(), applied_migration()}. -type apply_error() :: {already_applied, binary()} | {history_query_error, pog:query_error()} | {statement_error, binary(), pog:query_error()} | {record_error, pog:query_error()}. -file("src\\galchemy\\schema\\migration\\postgres.gleam", 39). -spec plan( binary(), galchemy@schema@model:schema_snapshot(), galchemy@schema@model:schema_snapshot() ) -> {ok, migration_plan()} | {error, galchemy@schema@ddl@postgres:ddl_compile_error()}. plan(Name, Current, Target) -> Operations = galchemy@schema@diff:diff(Current, Target), gleam@result:'try'( galchemy@schema@ddl@postgres:compile(Operations), fun(Statements) -> {ok, {migration_plan, Name, Operations, Statements}} end ). -file("src\\galchemy\\schema\\migration\\postgres.gleam", 182). -spec execute_unit_query( pog:'query'(any()), pog:connection(), fun((pog:query_error()) -> OSX) ) -> {ok, nil} | {error, OSX}. execute_unit_query(Query, Connection, Map_error) -> case pog:execute(Query, Connection) of {ok, _} -> {ok, nil}; {error, Error} -> {error, Map_error(Error)} end. -file("src\\galchemy\\schema\\migration\\postgres.gleam", 163). -spec apply_statements(list(binary()), pog:connection()) -> {ok, nil} | {error, apply_error()}. apply_statements(Statements, Connection) -> case Statements of [] -> {ok, nil}; [Statement | Rest] -> case execute_unit_query( pog:'query'(Statement), Connection, fun(Error) -> {statement_error, Statement, Error} end ) of {error, Error@1} -> {error, Error@1}; {ok, _} -> apply_statements(Rest, Connection) end end. -file("src\\galchemy\\schema\\migration\\postgres.gleam", 193). -spec find_applied(list(applied_migration()), binary()) -> gleam@option:option(applied_migration()). find_applied(Applied, Name) -> case Applied of [] -> none; [Migration | Rest] -> case erlang:element(2, Migration) =:= Name of true -> {some, Migration}; false -> find_applied(Rest, Name) end end. -file("src\\galchemy\\schema\\migration\\postgres.gleam", 208). -spec applied_migration_decoder() -> gleam@dynamic@decode:decoder(applied_migration()). applied_migration_decoder() -> _pipe = gleam@dynamic@decode:at( [0], {decoder, fun gleam@dynamic@decode:decode_string/1} ), gleam@dynamic@decode:then( _pipe, fun(Name) -> _pipe@1 = gleam@dynamic@decode:at( [1], {decoder, fun gleam@dynamic@decode:decode_string/1} ), gleam@dynamic@decode:then( _pipe@1, fun(Applied_at) -> _pipe@2 = gleam@dynamic@decode:at( [2], {decoder, fun gleam@dynamic@decode:decode_int/1} ), gleam@dynamic@decode:map( _pipe@2, fun(Statement_count) -> {applied_migration, Name, Applied_at, Statement_count} end ) end ) end ). -file("src\\galchemy\\schema\\migration\\postgres.gleam", 231). -spec compile_identifier(binary()) -> binary(). compile_identifier(Identifier) -> <<<<"\""/utf8, (gleam@string:replace(Identifier, <<"\""/utf8>>, <<"\"\""/utf8>>))/binary>>/binary, "\""/utf8>>. -file("src\\galchemy\\schema\\migration\\postgres.gleam", 239). -spec reverse_loop(list(OTG), list(OTG)) -> list(OTG). reverse_loop(Items, Acc) -> case Items of [] -> Acc; [Item | Rest] -> reverse_loop(Rest, [Item | Acc]) end. -file("src\\galchemy\\schema\\migration\\postgres.gleam", 235). -spec reverse(list(OTD)) -> list(OTD). reverse(Items) -> reverse_loop(Items, []). -file("src\\galchemy\\schema\\migration\\postgres.gleam", 133). -spec statuses_loop( list(migration_plan()), list(applied_migration()), list(migration_status()) ) -> list(migration_status()). statuses_loop(Plans, Applied, Acc) -> case Plans of [] -> reverse(Acc); [Plan | Rest] -> Next_status = case find_applied(Applied, erlang:element(2, Plan)) of {some, Record} -> {applied, Plan, Record}; none -> {pending, Plan} end, statuses_loop(Rest, Applied, [Next_status | Acc]) end. -file("src\\galchemy\\schema\\migration\\postgres.gleam", 92). -spec statuses(list(migration_plan()), list(applied_migration())) -> list(migration_status()). statuses(Plans, Applied) -> statuses_loop(Plans, Applied, []). -file("src\\galchemy\\schema\\migration\\postgres.gleam", 225). -spec compile_history_table_ref() -> binary(). compile_history_table_ref() -> <<<<(compile_identifier(<<"public"/utf8>>))/binary, "."/utf8>>/binary, (compile_identifier(<<"galchemy_schema_migrations"/utf8>>))/binary>>. -file("src\\galchemy\\schema\\migration\\postgres.gleam", 49). -spec ensure_history_table_query() -> pog:'query'(nil). ensure_history_table_query() -> pog:'query'( <<<<<<<<<<<<"CREATE TABLE IF NOT EXISTS "/utf8, (compile_history_table_ref())/binary>>/binary, " ("/utf8>>/binary, "\"name\" TEXT PRIMARY KEY, "/utf8>>/binary, "\"applied_at\" TIMESTAMP WITH TIME ZONE NOT NULL DEFAULT NOW(), "/utf8>>/binary, "\"statement_count\" INTEGER NOT NULL"/utf8>>/binary, ")"/utf8>> ). -file("src\\galchemy\\schema\\migration\\postgres.gleam", 61). -spec history_query() -> pog:'query'(applied_migration()). history_query() -> _pipe = pog:'query'( <<<<<<"SELECT \"name\", \"applied_at\"::text, \"statement_count\" "/utf8, "FROM "/utf8>>/binary, (compile_history_table_ref())/binary>>/binary, " ORDER BY \"applied_at\", \"name\""/utf8>> ), pog:returning(_pipe, applied_migration_decoder()). -file("src\\galchemy\\schema\\migration\\postgres.gleam", 71). -spec applied_migration_query(binary()) -> pog:'query'(applied_migration()). applied_migration_query(Name) -> _pipe = pog:'query'( <<<<<<"SELECT \"name\", \"applied_at\"::text, \"statement_count\" "/utf8, "FROM "/utf8>>/binary, (compile_history_table_ref())/binary>>/binary, " WHERE \"name\" = $1"/utf8>> ), _pipe@1 = pog:parameter(_pipe, pog_ffi:coerce(Name)), pog:returning(_pipe@1, applied_migration_decoder()). -file("src\\galchemy\\schema\\migration\\postgres.gleam", 82). -spec record_migration_query(migration_plan()) -> pog:'query'(nil). record_migration_query(Plan) -> _pipe = pog:'query'( <<<<"INSERT INTO "/utf8, (compile_history_table_ref())/binary>>/binary, " (\"name\", \"statement_count\") VALUES ($1, $2)"/utf8>> ), _pipe@1 = pog:parameter(_pipe, pog_ffi:coerce(erlang:element(2, Plan))), pog:parameter( _pipe@1, pog_ffi:coerce(erlang:length(erlang:element(4, Plan))) ). -file("src\\galchemy\\schema\\migration\\postgres.gleam", 151). -spec fetch_applied_migration(pog:connection(), binary()) -> {ok, gleam@option:option(applied_migration())} | {error, apply_error()}. fetch_applied_migration(Connection, Name) -> case pog:execute(applied_migration_query(Name), Connection) of {ok, {returned, 0, _}} -> {ok, none}; {ok, {returned, _, []}} -> {ok, none}; {ok, {returned, _, [First | _]}} -> {ok, {some, First}}; {error, Error} -> {error, {history_query_error, Error}} end. -file("src\\galchemy\\schema\\migration\\postgres.gleam", 99). -spec apply(pog:connection(), migration_plan()) -> {ok, nil} | {error, pog:transaction_error(apply_error())}. apply(Connection, Plan) -> pog:transaction( Connection, fun(Tx_connection) -> case execute_unit_query( ensure_history_table_query(), Tx_connection, fun(Field@0) -> {history_query_error, Field@0} end ) of {error, Error} -> {error, Error}; {ok, _} -> case fetch_applied_migration( Tx_connection, erlang:element(2, Plan) ) of {error, Error@1} -> {error, Error@1}; {ok, {some, _}} -> {error, {already_applied, erlang:element(2, Plan)}}; {ok, none} -> case apply_statements( erlang:element(4, Plan), Tx_connection ) of {error, Error@2} -> {error, Error@2}; {ok, _} -> execute_unit_query( record_migration_query(Plan), Tx_connection, fun(Field@0) -> {record_error, Field@0} end ) end end end end ).