-module(squirrel@internal@database@postgres). -compile([no_auto_import, nowarn_unused_vars, nowarn_unused_function, nowarn_nomatch, inline]). -define(FILEPATH, "src/squirrel/internal/database/postgres.gleam"). -export([main/2]). -export_type([pg_type/0, context/0, nullability/0, plan/0, join_type/0, connection_options/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. ?MODULEDOC(false). -type pg_type() :: {p_base, binary()} | {p_array, pg_type()} | {p_enum, binary(), list(binary())} | {p_option, pg_type()}. -type context() :: {context, squirrel@internal@database@postgres_protocol:connection(), gleam@dict:dict(integer(), squirrel@internal@gleam:type()), gleam@dict:dict({integer(), integer()}, nullability())}. -type nullability() :: nullable | not_nullable. -type plan() :: {plan, gleam@option:option(join_type()), list(binary()), list(plan())}. -type join_type() :: full_join | left_join | right_join | inner_join | semi_join. -type connection_options() :: {connection_options, binary(), integer(), binary(), binary(), binary(), integer()}. -file("src/squirrel/internal/database/postgres.gleam", 41). ?DOC(false). -spec find_postgres_type_query() -> squirrel@internal@query:untyped_query(). find_postgres_type_query() -> Name@1 = case squirrel@internal@gleam:value_identifier( <<"find_postgres_type_query"/utf8>> ) of {ok, Name} -> Name; _assert_fail -> erlang:error(#{gleam_error => let_assert, message => <<"Pattern match failed, no pattern matched the value."/utf8>>, file => <>, module => <<"squirrel/internal/database/postgres"/utf8>>, function => <<"find_postgres_type_query"/utf8>>, line => 42, value => _assert_fail, start => 1456, 'end' => 1528, pattern_start => 1467, pattern_end => 1475}) end, {untyped_query, <<""/utf8>>, 1, Name@1, [], <<" select -- The name of the type or, if the type is an array, the name of its -- elements' type. case when elem.typname is null then type.typname else elem.typname end as type, -- The oid of the type or the array item type. case when elem.typname is null then type.oid else elem.oid end as oid, -- Tells us how to interpret the first column: if this is true then the first -- column is the type of the elements of the array type. -- Otherwise it means we've found a base type. case when elem.typname is null then false else true end as is_array, -- The type of the type/array item. -- It will be 'e' if the thing is an enum. case when elem.typname is null then type.typtype else elem.typtype end as kind from pg_type as type left join pg_type as elem on type.typelem = elem.oid where type.oid = $1 "/utf8>>}. -file("src/squirrel/internal/database/postgres.gleam", 87). ?DOC(false). -spec find_enum_variants_query() -> squirrel@internal@query:untyped_query(). find_enum_variants_query() -> Name@1 = case squirrel@internal@gleam:value_identifier( <<"find_enum_variants_query"/utf8>> ) of {ok, Name} -> Name; _assert_fail -> erlang:error(#{gleam_error => let_assert, message => <<"Pattern match failed, no pattern matched the value."/utf8>>, file => <>, module => <<"squirrel/internal/database/postgres"/utf8>>, function => <<"find_enum_variants_query"/utf8>>, line => 88, value => _assert_fail, start => 2560, 'end' => 2632, pattern_start => 2571, pattern_end => 2579}) end, {untyped_query, <<""/utf8>>, 1, Name@1, [], <<" select enumlabel from pg_enum where enumtypid = $1 order by enumsortorder asc "/utf8>>}. -file("src/squirrel/internal/database/postgres.gleam", 108). ?DOC(false). -spec find_column_nullability_query() -> squirrel@internal@query:untyped_query(). find_column_nullability_query() -> Name@1 = case squirrel@internal@gleam:value_identifier( <<"find_column_nullability_query"/utf8>> ) of {ok, Name} -> Name; _assert_fail -> erlang:error(#{gleam_error => let_assert, message => <<"Pattern match failed, no pattern matched the value."/utf8>>, file => <>, module => <<"squirrel/internal/database/postgres"/utf8>>, function => <<"find_column_nullability_query"/utf8>>, line => 109, value => _assert_fail, start => 2882, 'end' => 2959, pattern_start => 2893, pattern_end => 2901}) end, {untyped_query, <<""/utf8>>, 1, Name@1, [], <<" select -- Whether the column has a not-null constraint. attnotnull from pg_attribute where -- The oid of the table the column comes from. attrelid = $1 -- The index of the column we're looking for. and attnum = $2 "/utf8>>}. -file("src/squirrel/internal/database/postgres.gleam", 131). ?DOC(false). -spec find_postgres_version_query() -> squirrel@internal@query:untyped_query(). find_postgres_version_query() -> Name@1 = case squirrel@internal@gleam:value_identifier( <<"find_postgres_version_query"/utf8>> ) of {ok, Name} -> Name; _assert_fail -> erlang:error(#{gleam_error => let_assert, message => <<"Pattern match failed, no pattern matched the value."/utf8>>, file => <>, module => <<"squirrel/internal/database/postgres"/utf8>>, function => <<"find_postgres_version_query"/utf8>>, line => 132, value => _assert_fail, start => 3353, 'end' => 3428, pattern_start => 3364, pattern_end => 3372}) end, {untyped_query, <<""/utf8>>, 1, Name@1, [], <<"select current_setting('server_version_num')"/utf8>>}. -file("src/squirrel/internal/database/postgres.gleam", 523). ?DOC(false). -spec check_sasl_final_message(bitstring(), bitstring(), binary()) -> eval:eval(nil, squirrel@internal@error:error(), context()). check_sasl_final_message(Msg, Expected_server_proof, User) -> case squirrel@internal@scram:parse_server_final(Msg) of {error, nil} -> eval:throw(pg_invalid_sha256_server_proof); {ok, {failed, _}} -> eval:throw({pg_invalid_password, User}); {ok, {successful, Server_proof}} -> case Server_proof =:= Expected_server_proof of true -> eval:return(nil); false -> eval:throw(pg_invalid_sha256_server_proof) end end. -file("src/squirrel/internal/database/postgres.gleam", 880). ?DOC(false). -spec plan_outputs_indices(plan(), gleam@dict:dict(binary(), integer())) -> gleam@set:set(integer()). plan_outputs_indices(Plan, Query_outputs) -> gleam@list:fold( erlang:element(3, Plan), gleam@set:new(), fun(Nullables, Output) -> case gleam_stdlib:map_get(Query_outputs, Output) of {ok, I} -> gleam@set:insert(Nullables, I); {error, _} -> Nullables end end ). -file("src/squirrel/internal/database/postgres.gleam", 827). ?DOC(false). -spec do_nullables_from_plan( plan(), gleam@dict:dict(binary(), integer()), gleam@set:set(integer()) ) -> gleam@set:set(integer()). do_nullables_from_plan(Plan, Query_outputs, Nullables) -> case {erlang:element(2, Plan), erlang:element(4, Plan)} of {{some, full_join}, _} -> _pipe = plan_outputs_indices(Plan, Query_outputs), gleam@set:union(_pipe, Nullables); {{some, right_join}, [Left, Right]} -> Nullables@1 = begin _pipe@1 = plan_outputs_indices(Left, Query_outputs), gleam@set:union(_pipe@1, Nullables) end, do_nullables_from_plan(Right, Query_outputs, Nullables@1); {{some, left_join}, [Left@1, Right@1]} -> Nullables@2 = begin _pipe@2 = plan_outputs_indices(Right@1, Query_outputs), gleam@set:union(_pipe@2, Nullables) end, do_nullables_from_plan(Left@1, Query_outputs, Nullables@2); {{some, semi_join}, [Left@1, Right@1]} -> Nullables@2 = begin _pipe@2 = plan_outputs_indices(Right@1, Query_outputs), gleam@set:union(_pipe@2, Nullables) end, do_nullables_from_plan(Left@1, Query_outputs, Nullables@2); {{some, right_join}, Plans} -> gleam@list:fold( Plans, Nullables, fun(Nullables@3, Plan@1) -> do_nullables_from_plan(Plan@1, Query_outputs, Nullables@3) end ); {{some, left_join}, Plans} -> gleam@list:fold( Plans, Nullables, fun(Nullables@3, Plan@1) -> do_nullables_from_plan(Plan@1, Query_outputs, Nullables@3) end ); {{some, semi_join}, Plans} -> gleam@list:fold( Plans, Nullables, fun(Nullables@3, Plan@1) -> do_nullables_from_plan(Plan@1, Query_outputs, Nullables@3) end ); {none, Plans} -> gleam@list:fold( Plans, Nullables, fun(Nullables@3, Plan@1) -> do_nullables_from_plan(Plan@1, Query_outputs, Nullables@3) end ); {{some, inner_join}, Plans@1} -> gleam@list:fold( Plans@1, Nullables, fun(Nullables@4, Plan@2) -> do_nullables_from_plan(Plan@2, Query_outputs, Nullables@4) end ) end. -file("src/squirrel/internal/database/postgres.gleam", 822). ?DOC(false). -spec nullables_from_plan(plan()) -> gleam@set:set(integer()). nullables_from_plan(Plan) -> Outputs = gleam@list:index_fold( erlang:element(3, Plan), maps:new(), fun gleam@dict:insert/3 ), do_nullables_from_plan(Plan, Outputs, gleam@set:new()). -file("src/squirrel/internal/database/postgres.gleam", 1130). ?DOC(false). -spec fields_to_permission_denied_error( binary(), gleam@set:set(squirrel@internal@database@postgres_protocol:error_or_notice_field()) ) -> {ok, squirrel@internal@error:error()} | {error, nil}. fields_to_permission_denied_error(Query_file, Fields) -> {Code@2, Reason@2} = begin gleam@set:fold( Fields, {none, none}, fun(_use0, Field) -> {Code, Reason} = _use0, case Field of {code, Code@1} -> {{some, Code@1}, Reason}; {message, Reason@1} -> {Code, {some, Reason@1}}; _ -> {Code, Reason} end end ) end, case {Code@2, Reason@2} of {{some, <<"42501"/utf8>>}, {some, Reason@3}} -> {ok, {pg_permission_denied, Query_file, Reason@3}}; {_, _} -> {error, nil} end. -file("src/squirrel/internal/database/postgres.gleam", 1151). ?DOC(false). -spec 'receive'() -> eval:eval(squirrel@internal@database@postgres_protocol:backend_message(), squirrel@internal@error:error(), context()). 'receive'() -> eval:from( fun(_use0) -> {context, Db, _, _} = Context = _use0, case squirrel@internal@database@postgres_protocol:'receive'(Db) of {ok, {Db@1, Msg}} -> {{context, Db@1, erlang:element(3, Context), erlang:element(4, Context)}, {ok, Msg}}; {error, {read_decode_error, Error}} -> {Context, {error, {pg_cannot_decode_received_message, gleam@string:inspect(Error)}}}; {error, {socket_error, Error@1}} -> {Context, {error, {pg_cannot_receive_message, gleam@string:inspect(Error@1)}}} end end ). -file("src/squirrel/internal/database/postgres.gleam", 1060). ?DOC(false). -spec do_accumulate_data_rows_until_command_complete( binary(), list(list(bitstring())) ) -> eval:eval(list(list(bitstring())), squirrel@internal@error:error(), context()). do_accumulate_data_rows_until_command_complete(Query_file, Acc) -> eval:'try'('receive'(), fun(Msg) -> case Msg of {be_command_complete, _, _} -> eval:return(lists:reverse(Acc)); {be_message_data_row, Data} -> do_accumulate_data_rows_until_command_complete( Query_file, [Data | Acc] ); {be_error_response, Fields} -> case fields_to_permission_denied_error(Query_file, Fields) of {ok, Error} -> eval:throw(Error); {error, _} -> erlang:error(#{gleam_error => panic, message => gleam@string:inspect(Msg), file => <>, module => <<"squirrel/internal/database/postgres"/utf8>>, function => <<"do_accumulate_data_rows_until_command_complete"/utf8>>, line => 1072}) end; _ -> erlang:error(#{gleam_error => panic, message => gleam@string:inspect(Msg), file => <>, module => <<"squirrel/internal/database/postgres"/utf8>>, function => <<"do_accumulate_data_rows_until_command_complete"/utf8>>, line => 1074}) end end). -file("src/squirrel/internal/database/postgres.gleam", 1056). ?DOC(false). -spec accumulate_data_rows_until_command_complete(binary()) -> eval:eval(list(list(bitstring())), squirrel@internal@error:error(), context()). accumulate_data_rows_until_command_complete(Query_file) -> do_accumulate_data_rows_until_command_complete(Query_file, []). -file("src/squirrel/internal/database/postgres.gleam", 1168). ?DOC(false). -spec send(squirrel@internal@database@postgres_protocol:frontend_message()) -> eval:eval(nil, squirrel@internal@error:error(), context()). send(Message) -> eval:from( fun(_use0) -> {context, Db, _, _} = Context = _use0, Result = begin _pipe = Message, _pipe@1 = squirrel@internal@database@postgres_protocol:encode_frontend_message( _pipe ), squirrel@internal@database@postgres_protocol:send(Db, _pipe@1) end, {Db@2, Result@1} = case Result of {ok, Db@1} -> {Db@1, {ok, nil}}; {error, Error} -> {Db, {error, {pg_cannot_send_message, gleam@string:inspect(Error)}}} end, {{context, Db@2, erlang:element(3, Context), erlang:element(4, Context)}, Result@1} end ). -file("src/squirrel/internal/database/postgres.gleam", 1189). ?DOC(false). -spec send_all( list(squirrel@internal@database@postgres_protocol:frontend_message()) ) -> eval:eval(nil, squirrel@internal@error:error(), context()). send_all(Messages) -> squirrel@internal@eval_extra:try_fold( Messages, nil, fun(Acc, Msg) -> eval:'try'(send(Msg), fun(_) -> eval:return(Acc) end) end ). -file("src/squirrel/internal/database/postgres.gleam", 1203). ?DOC(false). -spec do_wait_until_ready() -> eval:eval(nil, squirrel@internal@error:error(), context()). do_wait_until_ready() -> eval:'try'('receive'(), fun(Msg) -> case Msg of {be_ready_for_query, _} -> eval:return(nil); _ -> do_wait_until_ready() end end). -file("src/squirrel/internal/database/postgres.gleam", 1198). ?DOC(false). -spec wait_until_ready() -> eval:eval(nil, squirrel@internal@error:error(), context()). wait_until_ready() -> eval:'try'(send(fe_flush), fun(_) -> do_wait_until_ready() end). -file("src/squirrel/internal/database/postgres.gleam", 1214). ?DOC(false). -spec unexpected_message( fun((binary(), binary()) -> squirrel@internal@error:error()), binary(), squirrel@internal@database@postgres_protocol:backend_message() ) -> eval:eval(any(), squirrel@internal@error:error(), any()). unexpected_message(Builder, Expected, Got) -> _pipe = Builder(Expected, gleam@string:inspect(Got)), eval:throw(_pipe). -file("src/squirrel/internal/database/postgres.gleam", 416). ?DOC(false). -spec cleartext_authenticate(binary(), binary()) -> eval:eval(nil, squirrel@internal@error:error(), context()). cleartext_authenticate(User, Password) -> eval:'try'( send({fe_ambigous, {fe_password_message, Password}}), fun(_) -> eval:'try'('receive'(), fun(Msg) -> case Msg of be_authentication_ok -> eval:return(nil); {be_error_response, _} -> eval:throw({pg_invalid_password, User}); _ -> unexpected_message( fun(Field@0, Field@1) -> {pg_unexpected_cleartext_auth_message, Field@0, Field@1} end, <<"AuthenticationOk ok ErrorRespose"/utf8>>, Msg ) end end) end ). -file("src/squirrel/internal/database/postgres.gleam", 483). ?DOC(false). -spec expect_sasl_continue_message( squirrel@internal@database@postgres_protocol:backend_message() ) -> eval:eval(bitstring(), squirrel@internal@error:error(), context()). expect_sasl_continue_message(Msg) -> case Msg of {be_authentication_s_a_s_l_continue, Server_first} -> eval:return(Server_first); _ -> unexpected_message( fun(Field@0, Field@1) -> {pg_unexpected_sha256_auth_message, Field@0, Field@1} end, <<"AuthenticationSASLContinue(server-first)"/utf8>>, Msg ) end. -file("src/squirrel/internal/database/postgres.gleam", 501). ?DOC(false). -spec expect_sasl_final_message( squirrel@internal@database@postgres_protocol:backend_message(), binary() ) -> eval:eval(bitstring(), squirrel@internal@error:error(), any()). expect_sasl_final_message(Msg, User) -> Unexpected_message = unexpected_message( fun(Field@0, Field@1) -> {pg_unexpected_sha256_auth_message, Field@0, Field@1} end, <<"AuthenticationSASLFinal or BeErrorResponse"/utf8>>, Msg ), case Msg of {be_authentication_s_a_s_l_final, Msg@1} -> eval:return(Msg@1); {be_error_response, Fields} -> case gleam@set:contains(Fields, {code, <<"28P01"/utf8>>}) of true -> eval:throw({pg_invalid_password, User}); false -> Unexpected_message end; _ -> Unexpected_message end. -file("src/squirrel/internal/database/postgres.gleam", 434). ?DOC(false). -spec sha_256_authenticate(binary(), binary()) -> eval:eval(nil, squirrel@internal@error:error(), context()). sha_256_authenticate(User, Password) -> Nonce = squirrel@internal@scram:nonce(), Client_first_msg = {client_first, User, Nonce}, eval:'try'( begin _pipe = squirrel@internal@scram:encode_client_first( Client_first_msg ), _pipe@1 = {fe_sasl_initial_response, <<"SCRAM-SHA-256"/utf8>>, _pipe}, _pipe@2 = {fe_ambigous, _pipe@1}, send(_pipe@2) end, fun(_) -> eval:'try'( 'receive'(), fun(Msg) -> eval:'try'( expect_sasl_continue_message(Msg), fun(Raw_server_first_msg) -> Server_first_msg@1 = case squirrel@internal@scram:parse_server_first( Raw_server_first_msg, Nonce ) of {ok, Server_first_msg} -> Server_first_msg; _assert_fail -> erlang:error(#{gleam_error => let_assert, message => <<"Pattern match failed, no pattern matched the value."/utf8>>, file => <>, module => <<"squirrel/internal/database/postgres"/utf8>>, function => <<"sha_256_authenticate"/utf8>>, line => 453, value => _assert_fail, start => 13806, 'end' => 13897, pattern_start => 13817, pattern_end => 13837}) end, Client_last_msg = {client_last, Client_first_msg, Server_first_msg@1, Password}, {Client_last_msg@1, Expected_server_proof} = squirrel@internal@scram:encode_client_last( Client_last_msg ), eval:'try'( begin _pipe@3 = Client_last_msg@1, _pipe@4 = {fe_sasl_response, _pipe@3}, _pipe@5 = {fe_ambigous, _pipe@4}, send(_pipe@5) end, fun(_) -> eval:'try'( 'receive'(), fun(Msg@1) -> eval:'try'( expect_sasl_final_message( Msg@1, User ), fun(Msg@2) -> check_sasl_final_message( Msg@2, Expected_server_proof, User ) end ) end ) end ) end ) end ) end ). -file("src/squirrel/internal/database/postgres.gleam", 1122). ?DOC(false). -spec expect_ready_for_query_then_throw( squirrel@internal@error:error(), fun((binary(), binary()) -> squirrel@internal@error:error()) ) -> eval:eval(any(), squirrel@internal@error:error(), context()). expect_ready_for_query_then_throw(Error, To_error) -> eval:'try'('receive'(), fun(Msg) -> case Msg of {be_ready_for_query, _} -> eval:throw(Error); _ -> unexpected_message( To_error, <<"BeReadyForQuery(_)"/utf8>>, Msg ) end end). -file("src/squirrel/internal/database/postgres.gleam", 1224). ?DOC(false). -spec unsupported_authentication(binary()) -> eval:eval(any(), squirrel@internal@error:error(), context()). unsupported_authentication(Auth) -> eval:throw({pg_unsupported_authentication, Auth}). -file("src/squirrel/internal/database/postgres.gleam", 355). ?DOC(false). -spec authenticate(binary(), binary(), binary()) -> eval:eval(nil, squirrel@internal@error:error(), context()). authenticate(User, Database, Password) -> Params = [{<<"user"/utf8>>, User}, {<<"database"/utf8>>, Database}], eval:'try'( send({fe_startup_message, Params}), fun(_) -> eval:'try'('receive'(), fun(Msg) -> eval:'try'(case Msg of be_authentication_ok -> eval:return(nil); be_authentication_cleartext_password -> cleartext_authenticate(User, Password); {be_authentication_m_d5_password, _} -> unsupported_authentication(<<"md5"/utf8>>); be_authentication_g_s_s -> unsupported_authentication(<<"GSS"/utf8>>); {be_authentication_s_a_s_l, Methods} -> case gleam@list:contains( Methods, <<"SCRAM-SHA-256"/utf8>> ) of true -> sha_256_authenticate(User, Password); _ -> _pipe = case gleam@list:filter( Methods, fun(Method) -> Method /= <<""/utf8>> end ) of [_ | _] -> <<<<"SASL("/utf8, (gleam@string:join( Methods, <<","/utf8>> ))/binary>>/binary, ")"/utf8>>; [] -> <<"SASL"/utf8>> end, unsupported_authentication(_pipe) end; be_authentication_s_s_p_i -> unsupported_authentication(<<"SSPI"/utf8>>); be_authentication_kerberos_v5 -> unsupported_authentication( <<"KerberosV5"/utf8>> ); _ -> unexpected_message( fun(Field@0, Field@1) -> {pg_unexpected_auth_method_message, Field@0, Field@1} end, <<"AuthMethod"/utf8>>, Msg ) end, fun(_) -> eval:'try'( begin _pipe@1 = wait_until_ready(), eval:replace_error( _pipe@1, {pg_invalid_user_database, User, Database} ) end, fun(_) -> eval:return(nil) end ) end) end) end ). -file("src/squirrel/internal/database/postgres.gleam", 1233). ?DOC(false). -spec with_cached_gleam_type( integer(), fun(() -> eval:eval(squirrel@internal@gleam:type(), squirrel@internal@error:error(), context())) ) -> eval:eval(squirrel@internal@gleam:type(), squirrel@internal@error:error(), context()). with_cached_gleam_type(Oid, Do) -> eval:from( fun(Context) -> case gleam_stdlib:map_get(erlang:element(3, Context), Oid) of {ok, Type_} -> {Context, {ok, Type_}}; {error, _} -> case eval:step(Do(), Context) of {_, {error, _}} = Result -> Result; {{context, _, Gleam_types, _} = Context@1, {ok, Type_@1}} -> Gleam_types@1 = gleam@dict:insert( Gleam_types, Oid, Type_@1 ), New_context = {context, erlang:element(2, Context@1), Gleam_types@1, erlang:element(4, Context@1)}, {New_context, {ok, Type_@1}} end end end ). -file("src/squirrel/internal/database/postgres.gleam", 1257). ?DOC(false). -spec with_cached_column( integer(), integer(), fun(() -> eval:eval(nullability(), squirrel@internal@error:error(), context())) ) -> eval:eval(nullability(), squirrel@internal@error:error(), context()). with_cached_column(Table_oid, Column, Do) -> eval:from( fun(Context) -> Key = {Table_oid, Column}, case gleam_stdlib:map_get(erlang:element(4, Context), Key) of {ok, Type_} -> {Context, {ok, Type_}}; {error, _} -> case eval:step(Do(), Context) of {_, {error, _}} = Result -> Result; {{context, _, _, Column_nullability} = Context@1, {ok, Type_@1}} -> Column_nullability@1 = gleam@dict:insert( Column_nullability, Key, Type_@1 ), New_context = {context, erlang:element(2, Context@1), erlang:element(3, Context@1), Column_nullability@1}, {New_context, {ok, Type_@1}} end end end ). -file("src/squirrel/internal/database/postgres.gleam", 1280). ?DOC(false). -spec unsupported_type_error(squirrel@internal@query:untyped_query(), binary()) -> squirrel@internal@error:error(). unsupported_type_error(Query, Type_) -> {untyped_query, File, Starting_line, Name, _, Content} = Query, {query_has_unsupported_type, File, squirrel@internal@gleam:value_identifier_to_string(Name), Content, Starting_line, Type_}. -file("src/squirrel/internal/database/postgres.gleam", 1291). ?DOC(false). -spec invalid_enum_error( squirrel@internal@query:untyped_query(), binary(), squirrel@internal@error:enum_error() ) -> squirrel@internal@error:error(). invalid_enum_error(Query, Enum_name, Reason) -> {untyped_query, File, Starting_line, _, _, Content} = Query, {query_has_invalid_enum, File, Content, Starting_line, Enum_name, Reason}. -file("src/squirrel/internal/database/postgres.gleam", 261). ?DOC(false). -spec pg_to_gleam_type(squirrel@internal@query:untyped_query(), pg_type()) -> {ok, squirrel@internal@gleam:type()} | {error, squirrel@internal@error:error()}. pg_to_gleam_type(Query, Type_) -> case Type_ of {p_array, Inner} -> _pipe = pg_to_gleam_type(Query, Inner), gleam@result:map(_pipe, fun(Field@0) -> {list, Field@0} end); {p_option, Inner@1} -> _pipe@1 = pg_to_gleam_type(Query, Inner@1), gleam@result:map(_pipe@1, fun(Field@0) -> {option, Field@0} end); {p_base, Name} -> case Name of <<"bool"/utf8>> -> {ok, bool}; <<"text"/utf8>> -> {ok, string}; <<"char"/utf8>> -> {ok, string}; <<"bpchar"/utf8>> -> {ok, string}; <<"varchar"/utf8>> -> {ok, string}; <<"float4"/utf8>> -> {ok, float}; <<"float8"/utf8>> -> {ok, float}; <<"numeric"/utf8>> -> {ok, numeric}; <<"int2"/utf8>> -> {ok, int}; <<"int4"/utf8>> -> {ok, int}; <<"int8"/utf8>> -> {ok, int}; <<"json"/utf8>> -> {ok, json}; <<"jsonb"/utf8>> -> {ok, json}; <<"uuid"/utf8>> -> {ok, uuid}; <<"bytea"/utf8>> -> {ok, bit_array}; <<"date"/utf8>> -> {ok, date}; <<"time"/utf8>> -> {ok, time_of_day}; <<"timestamp"/utf8>> -> {ok, timestamp}; _ -> {error, unsupported_type_error(Query, Name)} end; {p_enum, Name@1, Variants} -> _pipe@2 = squirrel@internal@gleam:try_make_enum(Name@1, Variants), gleam@result:map_error( _pipe@2, fun(_capture) -> invalid_enum_error(Query, Name@1, _capture) end ) end. -file("src/squirrel/internal/database/postgres.gleam", 1302). ?DOC(false). -spec cannot_parse_error( squirrel@internal@query:untyped_query(), gleam@option:option(binary()), gleam@option:option(binary()), gleam@option:option(binary()), gleam@option:option(squirrel@internal@error:pointer()) ) -> squirrel@internal@error:error(). cannot_parse_error(Query, Error_code, Hint, Additional_error_message, Pointer) -> {untyped_query, File, Starting_line, Name, _, Content} = Query, {cannot_parse_query, File, squirrel@internal@gleam:value_identifier_to_string(Name), Content, Starting_line, Error_code, Pointer, Additional_error_message, Hint}. -file("src/squirrel/internal/database/postgres.gleam", 652). ?DOC(false). -spec error_fields_to_parse_error( squirrel@internal@query:untyped_query(), gleam@set:set(squirrel@internal@database@postgres_protocol:error_or_notice_field()) ) -> squirrel@internal@error:error(). error_fields_to_parse_error(Query, Errors) -> {Error_code, Message@2, Position@3, Hint@2} = begin gleam@set:fold( Errors, {none, none, none, none}, fun(Acc, Error_field) -> {Code, Message, Position, Hint} = Acc, case Error_field of {code, Code@1} -> {{some, Code@1}, Message, Position, Hint}; {message, Message@1} -> {Code, {some, Message@1}, Position, Hint}; {hint, Hint@1} -> {Code, Message, Position, {some, Hint@1}}; {position, Position@1} -> case gleam_stdlib:parse_int(Position@1) of {ok, Position@2} -> {Code, Message, {some, Position@2}, Hint}; {error, _} -> Acc end; _ -> Acc end end ) end, {Pointer, Additional_error_message} = case {Message@2, Position@3} of {{some, Message@3}, {some, Position@4}} -> {{some, {pointer, {byte_index, Position@4}, Message@3}}, none}; {{some, Message@4}, none} -> {none, {some, Message@4}}; {_, _} -> {none, none} end, cannot_parse_error( Query, Error_code, Hint@2, Additional_error_message, Pointer ). -file("src/squirrel/internal/database/postgres.gleam", 580). ?DOC(false). -spec parameters_and_returns(squirrel@internal@query:untyped_query()) -> eval:eval({list(integer()), list(squirrel@internal@database@postgres_protocol:row_description_field())}, squirrel@internal@error:error(), context()). parameters_and_returns(Query) -> eval:'try'( send_all( [{fe_parse, <<""/utf8>>, erlang:element(6, Query), []}, {fe_describe, prepared_statement, <<""/utf8>>}, fe_sync] ), fun(_) -> Cannot_describe = fun(Expected, Got) -> {pg_cannot_describe_query, erlang:element(2, Query), squirrel@internal@gleam:value_identifier_to_string( erlang:element(4, Query) ), Expected, Got} end, eval:'try'('receive'(), fun(Msg) -> case Msg of {be_error_response, Errors} -> eval:'try'('receive'(), fun(Msg@1) -> case Msg@1 of {be_ready_for_query, _} -> eval:throw( error_fields_to_parse_error( Query, Errors ) ); _ -> unexpected_message( Cannot_describe, <<"BeReadyForQuery(_)"/utf8>>, Msg@1 ) end end); be_parse_complete -> eval:'try'( 'receive'(), fun(Msg@2) -> eval:'try'(case Msg@2 of {be_parameter_description, Parameters} -> eval:return(Parameters); be_no_data -> eval:return([]); _ -> unexpected_message( Cannot_describe, <<"ParameterDescription"/utf8>>, Msg@2 ) end, fun(Parameters@1) -> eval:'try'( 'receive'(), fun(Msg@3) -> eval:'try'(case Msg@3 of {be_row_descriptions, Rows} -> eval:return( Rows ); be_no_data -> eval:return([]); _ -> unexpected_message( Cannot_describe, <<"RowDescriptions"/utf8>>, Msg@3 ) end, fun(Rows@1) -> eval:'try'( 'receive'(), fun(Msg@4) -> eval:'try'( case Msg@4 of {be_ready_for_query, _} -> eval:return( nil ); _ -> unexpected_message( Cannot_describe, <<"ReadyForQuery"/utf8>>, Msg@4 ) end, fun(_) -> eval:return( {Parameters@1, Rows@1} ) end ) end ) end) end ) end) end ); _ -> unexpected_message( Cannot_describe, <<"ParseComplete or ErrorResponse"/utf8>>, Msg ) end end) end ). -file("src/squirrel/internal/database/postgres.gleam", 1078). ?DOC(false). -spec expect_parse_complete( squirrel@internal@database@postgres_protocol:backend_message(), squirrel@internal@query:untyped_query() ) -> eval:eval(nil, squirrel@internal@error:error(), context()). expect_parse_complete(Msg, Query) -> case Msg of be_parse_complete -> eval:return(nil); {be_error_response, Fields} -> {untyped_query, File, _, Name, _, _} = Query, Query_name = squirrel@internal@gleam:value_identifier_to_string( Name ), Unexpected = fun(Expected, Got) -> {pg_cannot_describe_query, File, Query_name, Expected, Got} end, Parse_error = error_fields_to_parse_error(Query, Fields), expect_ready_for_query_then_throw(Parse_error, Unexpected); _ -> erlang:error(#{gleam_error => panic, message => gleam@string:inspect(Msg), file => <>, module => <<"squirrel/internal/database/postgres"/utf8>>, function => <<"expect_parse_complete"/utf8>>, line => 1092}) end. -file("src/squirrel/internal/database/postgres.gleam", 996). ?DOC(false). -spec run_query( squirrel@internal@query:untyped_query(), list(squirrel@internal@database@postgres_protocol:parameter_value()), list(integer()) ) -> eval:eval(list(list(bitstring())), squirrel@internal@error:error(), context()). run_query(Query, Parameters, Parameters_object_ids) -> eval:'try'( send_all( [{fe_parse, <<""/utf8>>, erlang:element(6, Query), Parameters_object_ids}, {fe_bind, <<""/utf8>>, <<""/utf8>>, {format_all, binary}, Parameters, {format_all, binary}}, {fe_execute, <<""/utf8>>, 0}, {fe_close, prepared_statement, <<""/utf8>>}, {fe_close, portal, <<""/utf8>>}, fe_sync] ), fun(_) -> eval:'try'( 'receive'(), fun(Msg) -> eval:'try'( expect_parse_complete(Msg, Query), fun(_) -> eval:'try'( 'receive'(), fun(Msg@1) -> case Msg@1 of be_bind_complete -> nil; _assert_fail -> erlang:error( #{gleam_error => let_assert, message => <<"Pattern match failed, no pattern matched the value."/utf8>>, file => <>, module => <<"squirrel/internal/database/postgres"/utf8>>, function => <<"run_query"/utf8>>, line => 1041, value => _assert_fail, start => 35023, 'end' => 35057, pattern_start => 35034, pattern_end => 35051} ) end, eval:'try'( accumulate_data_rows_until_command_complete( erlang:element(2, Query) ), fun(Res) -> eval:'try'( 'receive'(), fun(Msg@2) -> case Msg@2 of be_close_complete -> nil; _assert_fail@1 -> erlang:error( #{gleam_error => let_assert, message => <<"Pattern match failed, no pattern matched the value."/utf8>>, file => <>, module => <<"squirrel/internal/database/postgres"/utf8>>, function => <<"run_query"/utf8>>, line => 1044, value => _assert_fail@1, start => 35172, 'end' => 35207, pattern_start => 35183, pattern_end => 35201} ) end, eval:'try'( 'receive'(), fun(Msg@3) -> case Msg@3 of be_close_complete -> nil; _assert_fail@2 -> erlang:error( #{gleam_error => let_assert, message => <<"Pattern match failed, no pattern matched the value."/utf8>>, file => <>, module => <<"squirrel/internal/database/postgres"/utf8>>, function => <<"run_query"/utf8>>, line => 1046, value => _assert_fail@2, start => 35243, 'end' => 35278, pattern_start => 35254, pattern_end => 35272} ) end, eval:'try'( 'receive'(), fun(Msg@4) -> case Msg@4 of {be_ready_for_query, _} -> nil; _assert_fail@3 -> erlang:error( #{gleam_error => let_assert, message => <<"Pattern match failed, no pattern matched the value."/utf8>>, file => <>, module => <<"squirrel/internal/database/postgres"/utf8>>, function => <<"run_query"/utf8>>, line => 1048, value => _assert_fail@3, start => 35314, 'end' => 35352, pattern_start => 35325, pattern_end => 35346} ) end, eval:return( Res ) end ) end ) end ) end ) end ) end ) end ) end ). -file("src/squirrel/internal/database/postgres.gleam", 752). ?DOC(false). -spec resolve_enum_type(binary(), integer()) -> eval:eval(pg_type(), squirrel@internal@error:error(), context()). resolve_enum_type(Name, Oid) -> Params = [{parameter, <>}], eval:'try'( run_query(find_enum_variants_query(), Params, [23]), fun(Rows) -> Variants = gleam@list:map( Rows, fun(Row) -> Variant@1 = case Row of [Variant] -> Variant; _assert_fail -> erlang:error(#{gleam_error => let_assert, message => <<"Pattern match failed, no pattern matched the value."/utf8>>, file => <>, module => <<"squirrel/internal/database/postgres"/utf8>>, function => <<"resolve_enum_type"/utf8>>, line => 759, value => _assert_fail, start => 25033, 'end' => 25059, pattern_start => 25044, pattern_end => 25053}) end, Variant@3 = case gleam@bit_array:to_string(Variant@1) of {ok, Variant@2} -> Variant@2; _assert_fail@1 -> erlang:error(#{gleam_error => let_assert, message => <<"Pattern match failed, no pattern matched the value."/utf8>>, file => <>, module => <<"squirrel/internal/database/postgres"/utf8>>, function => <<"resolve_enum_type"/utf8>>, line => 760, value => _assert_fail@1, start => 25066, 'end' => 25119, pattern_start => 25077, pattern_end => 25088}) end, Variant@3 end ), eval:return({p_enum, Name, Variants}) end ). -file("src/squirrel/internal/database/postgres.gleam", 1322). ?DOC(false). -spec invalid_column_error( squirrel@internal@query:untyped_query(), binary(), squirrel@internal@error:value_identifier_error() ) -> squirrel@internal@error:error(). invalid_column_error(Query, Column_name, Reason) -> {untyped_query, File, Starting_line, _, _, Content} = Query, {query_has_invalid_column, File, Column_name, begin _pipe = squirrel@internal@gleam:similar_value_identifier_string( Column_name ), gleam@option:from_result(_pipe) end, Content, Starting_line, Reason}. -file("src/squirrel/internal/database/postgres.gleam", 1358). ?DOC(false). -spec adjust_parse_error_for_explain(squirrel@internal@error:error()) -> squirrel@internal@error:error(). adjust_parse_error_for_explain(Error) -> case Error of {cannot_parse_query, _, _, _, _, _, Pointer, _, _} -> Pointer@1 = case Pointer of {some, {pointer, {byte_index, Index}, Message}} -> {some, {pointer, {byte_index, Index - 45}, Message}}; _ -> Pointer end, {cannot_parse_query, erlang:element(2, Error), erlang:element(3, Error), erlang:element(4, Error), erlang:element(5, Error), erlang:element(6, Error), Pointer@1, erlang:element(8, Error), erlang:element(9, Error)}; _ -> Error end. -file("src/squirrel/internal/database/postgres.gleam", 1096). ?DOC(false). -spec expect_query_plan_row_description( squirrel@internal@database@postgres_protocol:backend_message(), squirrel@internal@query:untyped_query() ) -> eval:eval(nil, squirrel@internal@error:error(), context()). expect_query_plan_row_description(Msg, Query) -> case Msg of {be_row_descriptions, [{row_description_field, <<"QUERY PLAN"/utf8>>, _, _, _, _, _, _}]} -> eval:return(nil); {be_error_response, Fields} -> {untyped_query, File, _, Name, _, _} = Query, Query_name = squirrel@internal@gleam:value_identifier_to_string( Name ), Unexpected = fun(Expected, Got) -> {pg_cannot_explain_query, File, Query_name, Expected, Got} end, Parse_error = begin _pipe = error_fields_to_parse_error(Query, Fields), adjust_parse_error_for_explain(_pipe) end, expect_ready_for_query_then_throw(Parse_error, Unexpected); _ -> erlang:error(#{gleam_error => panic, message => gleam@string:inspect(Msg), file => <>, module => <<"squirrel/internal/database/postgres"/utf8>>, function => <<"expect_query_plan_row_description"/utf8>>, line => 1118}) end. -file("src/squirrel/internal/database/postgres.gleam", 802). ?DOC(false). -spec run_explain_query(squirrel@internal@query:untyped_query()) -> eval:eval(bitstring(), squirrel@internal@error:error(), context()). run_explain_query(Query) -> Explain_query = <<"explain (format json, verbose, generic_plan) "/utf8, (erlang:element(6, Query))/binary>>, eval:'try'( send_all([{fe_query, Explain_query}]), fun(_) -> eval:'try'( 'receive'(), fun(Msg) -> eval:'try'( expect_query_plan_row_description(Msg, Query), fun(_) -> eval:'try'( 'receive'(), fun(Msg@1) -> Query_plan@1 = case Msg@1 of {be_message_data_row, [Query_plan]} -> Query_plan; _assert_fail -> erlang:error( #{gleam_error => let_assert, message => <<"Pattern match failed, no pattern matched the value."/utf8>>, file => <>, module => <<"squirrel/internal/database/postgres"/utf8>>, function => <<"run_explain_query"/utf8>>, line => 811, value => _assert_fail, start => 26685, 'end' => 26735, pattern_start => 26696, pattern_end => 26729} ) end, eval:'try'( 'receive'(), fun(Msg@2) -> case Msg@2 of {be_command_complete, _, _} -> nil; _assert_fail@1 -> erlang:error( #{gleam_error => let_assert, message => <<"Pattern match failed, no pattern matched the value."/utf8>>, file => <>, module => <<"squirrel/internal/database/postgres"/utf8>>, function => <<"run_explain_query"/utf8>>, line => 813, value => _assert_fail@1, start => 26771, 'end' => 26814, pattern_start => 26782, pattern_end => 26808} ) end, eval:'try'( 'receive'(), fun(Msg@3) -> case Msg@3 of {be_ready_for_query, _} -> nil; _assert_fail@2 -> erlang:error( #{gleam_error => let_assert, message => <<"Pattern match failed, no pattern matched the value."/utf8>>, file => <>, module => <<"squirrel/internal/database/postgres"/utf8>>, function => <<"run_explain_query"/utf8>>, line => 815, value => _assert_fail@2, start => 26850, 'end' => 26888, pattern_start => 26861, pattern_end => 26882} ) end, eval:return(Query_plan@1) end ) end ) end ) end ) end ) end ). -file("src/squirrel/internal/database/postgres.gleam", 1389). ?DOC(false). -spec join_type_decoder() -> gleam@dynamic@decode:decoder(gleam@option:option(join_type())). join_type_decoder() -> gleam@dynamic@decode:then( {decoder, fun gleam@dynamic@decode:decode_string/1}, fun(Data) -> case Data of <<"Full"/utf8>> -> gleam@dynamic@decode:success({some, full_join}); <<"Left"/utf8>> -> gleam@dynamic@decode:success({some, left_join}); <<"Right"/utf8>> -> gleam@dynamic@decode:success({some, right_join}); <<"Inner"/utf8>> -> gleam@dynamic@decode:success({some, inner_join}); <<"Semi"/utf8>> -> gleam@dynamic@decode:success({some, semi_join}); _ -> gleam@dynamic@decode:failure(none, <<"JoinType"/utf8>>) end end ). -file("src/squirrel/internal/database/postgres.gleam", 1382). ?DOC(false). -spec plan_decoder() -> gleam@dynamic@decode:decoder(plan()). plan_decoder() -> gleam@dynamic@decode:optional_field( <<"Join Type"/utf8>>, none, join_type_decoder(), fun(Join_type) -> gleam@dynamic@decode:optional_field( <<"Output"/utf8>>, [], gleam@dynamic@decode:list( {decoder, fun gleam@dynamic@decode:decode_string/1} ), fun(Output) -> gleam@dynamic@decode:optional_field( <<"Plans"/utf8>>, [], gleam@dynamic@decode:list(plan_decoder()), fun(Plans) -> gleam@dynamic@decode:success( {plan, Join_type, Output, Plans} ) end ) end ) end ). -file("src/squirrel/internal/database/postgres.gleam", 1378). ?DOC(false). -spec json_plans_decoder() -> gleam@dynamic@decode:decoder(list(plan())). json_plans_decoder() -> gleam@dynamic@decode:list( gleam@dynamic@decode:at([<<"Plan"/utf8>>], plan_decoder()) ). -file("src/squirrel/internal/database/postgres.gleam", 770). ?DOC(false). -spec query_plan(squirrel@internal@query:untyped_query()) -> eval:eval(plan(), squirrel@internal@error:error(), context()). query_plan(Query) -> eval:'try'( run_explain_query(Query), fun(Plan) -> case gleam@json:parse_bits(Plan, json_plans_decoder()) of {ok, [Plan@1 | _]} -> eval:return(Plan@1); {ok, []} -> erlang:error(#{gleam_error => panic, message => <<"unreachable: no query plan"/utf8>>, file => <>, module => <<"squirrel/internal/database/postgres"/utf8>>, function => <<"query_plan"/utf8>>, line => 777}); {error, Reason} -> eval:throw( {cannot_parse_plan_for_query, erlang:element(2, Query), Reason} ) end end ). -file("src/squirrel/internal/database/postgres.gleam", 1406). ?DOC(false). -spec bit_array_to_bool(bitstring()) -> boolean(). bit_array_to_bool(Bit_array) -> case Bit_array of <<0, Rest/bitstring>> -> bit_array_to_bool(Rest); <<>> -> false; _ -> true end. -file("src/squirrel/internal/database/postgres.gleam", 715). ?DOC(false). -spec find_gleam_type(squirrel@internal@query:untyped_query(), integer()) -> eval:eval(squirrel@internal@gleam:type(), squirrel@internal@error:error(), context()). find_gleam_type(Query, Oid) -> with_cached_gleam_type( Oid, fun() -> Params = [{parameter, <>}], eval:'try'( run_query(find_postgres_type_query(), Params, [23]), fun(Res) -> {Name@1, Oid@2, Is_array@1, Kind@1} = case Res of [[Name, Oid@1, Is_array, Kind]] -> { Name, Oid@1, Is_array, Kind}; _assert_fail -> erlang:error(#{gleam_error => let_assert, message => <<"Pattern match failed, no pattern matched the value."/utf8>>, file => <>, module => <<"squirrel/internal/database/postgres"/utf8>>, function => <<"find_gleam_type"/utf8>>, line => 729, value => _assert_fail, start => 24110, 'end' => 24156, pattern_start => 24121, pattern_end => 24150}) end, Name@3 = case gleam@bit_array:to_string(Name@1) of {ok, Name@2} -> Name@2; _assert_fail@1 -> erlang:error(#{gleam_error => let_assert, message => <<"Pattern match failed, no pattern matched the value."/utf8>>, file => <>, module => <<"squirrel/internal/database/postgres"/utf8>>, function => <<"find_gleam_type"/utf8>>, line => 730, value => _assert_fail@1, start => 24159, 'end' => 24206, pattern_start => 24170, pattern_end => 24178}) end, Kind@3 = case gleam@bit_array:to_string(Kind@1) of {ok, Kind@2} -> Kind@2; _assert_fail@2 -> erlang:error(#{gleam_error => let_assert, message => <<"Pattern match failed, no pattern matched the value."/utf8>>, file => <>, module => <<"squirrel/internal/database/postgres"/utf8>>, function => <<"find_gleam_type"/utf8>>, line => 731, value => _assert_fail@2, start => 24209, 'end' => 24256, pattern_start => 24220, pattern_end => 24228}) end, Oid@4 = case Oid@2 of <> -> Oid@3; _assert_fail@3 -> erlang:error(#{gleam_error => let_assert, message => <<"Pattern match failed, no pattern matched the value."/utf8>>, file => <>, module => <<"squirrel/internal/database/postgres"/utf8>>, function => <<"find_gleam_type"/utf8>>, line => 732, value => _assert_fail@3, start => 24259, 'end' => 24292, pattern_start => 24270, pattern_end => 24286}) end, eval:'try'(case Kind@3 of <<"e"/utf8>> -> resolve_enum_type(Name@3, Oid@4); _ -> eval:return({p_base, Name@3}) end, fun(Type_) -> Type_@1 = case bit_array_to_bool(Is_array@1) of true -> {p_array, Type_}; false -> Type_ end, _pipe = pg_to_gleam_type(Query, Type_@1), eval:from_result(_pipe) end) end ) end ). -file("src/squirrel/internal/database/postgres.gleam", 701). ?DOC(false). -spec resolve_parameters( squirrel@internal@query:untyped_query(), list(integer()) ) -> eval:eval(list(squirrel@internal@gleam:type()), squirrel@internal@error:error(), context()). resolve_parameters(Query, Parameters) -> squirrel@internal@eval_extra:try_map( Parameters, fun(Oid) -> find_gleam_type(Query, Oid) end ). -file("src/squirrel/internal/database/postgres.gleam", 954). ?DOC(false). -spec column_nullability(integer(), integer()) -> eval:eval(nullability(), squirrel@internal@error:error(), context()). column_nullability(Table, Column) -> with_cached_column( Table, Column, fun() -> gleam@bool:guard( Table =:= 0, eval:return(not_nullable), fun() -> Params = [{parameter, <>}, {parameter, <>}], Run_query = run_query( find_column_nullability_query(), Params, [23, 23] ), eval:'try'( Run_query, fun(Res) -> Has_non_null_constraint@1 = case Res of [[Has_non_null_constraint]] -> Has_non_null_constraint; _assert_fail -> erlang:error(#{gleam_error => let_assert, message => <<"Pattern match failed, no pattern matched the value."/utf8>>, file => <>, module => <<"squirrel/internal/database/postgres"/utf8>>, function => <<"column_nullability"/utf8>>, line => 972, value => _assert_fail, start => 32230, 'end' => 32274, pattern_start => 32241, pattern_end => 32268}) end, case bit_array_to_bool(Has_non_null_constraint@1) of true -> eval:return(not_nullable); false -> eval:return(nullable) end end ) end ) end ). -file("src/squirrel/internal/database/postgres.gleam", 902). ?DOC(false). -spec resolve_returns( squirrel@internal@query:untyped_query(), list(squirrel@internal@database@postgres_protocol:row_description_field()), gleam@set:set(integer()) ) -> eval:eval(list(squirrel@internal@gleam:field()), squirrel@internal@error:error(), context()). resolve_returns(Query, Returns, Nullables) -> squirrel@internal@eval_extra:try_index_map( Returns, fun(Column, I) -> {row_description_field, Name, Table, Column@1, Type_oid, _, _, _} = Column, eval:'try'( find_gleam_type(Query, Type_oid), fun(Type_) -> Ends_with_exclamation_mark = gleam_stdlib:string_ends_with( Name, <<"!"/utf8>> ), Ends_with_question_mark = gleam_stdlib:string_ends_with( Name, <<"?"/utf8>> ), eval:'try'(case Ends_with_exclamation_mark of true -> eval:return(not_nullable); false -> case Ends_with_question_mark of true -> eval:return(nullable); false -> case gleam@set:contains(Nullables, I) of true -> eval:return(nullable); false -> column_nullability( Table, Column@1 ) end end end, fun(Nullability) -> Type_@1 = case Nullability of nullable -> {option, Type_}; not_nullable -> Type_ end, Try_convert_name = begin _pipe = case Ends_with_exclamation_mark orelse Ends_with_question_mark of true -> gleam@string:drop_end(Name, 1); false -> Name end, _pipe@1 = squirrel@internal@gleam:value_identifier( _pipe ), gleam@result:map_error( _pipe@1, fun(_capture) -> invalid_column_error( Query, Name, _capture ) end ) end, eval:'try'( eval:from_result(Try_convert_name), fun(Name@1) -> Field = {field, Name@1, Type_@1}, eval:return(Field) end ) end) end ) end ). -file("src/squirrel/internal/database/postgres.gleam", 541). ?DOC(false). -spec infer_types(squirrel@internal@query:untyped_query()) -> eval:eval(squirrel@internal@query:typed_query(), squirrel@internal@error:error(), context()). infer_types(Query) -> eval:'try'( parameters_and_returns(Query), fun(_use0) -> {Parameters, Returns} = _use0, eval:'try'( resolve_parameters(Query, Parameters), fun(Parameters@1) -> eval:'try'( eval:attempt( eval:map( query_plan(Query), fun nullables_from_plan/1 ), fun(_, _) -> eval:return(gleam@set:new()) end ), fun(Nullables) -> eval:'try'( resolve_returns(Query, Returns, Nullables), fun(Returns@1) -> _pipe = Query, _pipe@1 = squirrel@internal@query:add_types( _pipe, Parameters@1, Returns@1 ), eval:from_result(_pipe@1) end ) end ) end ) end ). -file("src/squirrel/internal/database/postgres.gleam", 404). ?DOC(false). -spec ensure_postgres_version() -> eval:eval(nil, squirrel@internal@error:error(), context()). ensure_postgres_version() -> eval:'try'( run_query(find_postgres_version_query(), [], []), fun(Version) -> Version@2 = case Version of [[Version@1 | _] | _] -> Version@1; _assert_fail -> erlang:error(#{gleam_error => let_assert, message => <<"select version should always return at least one row"/utf8>>, file => <>, module => <<"squirrel/internal/database/postgres"/utf8>>, function => <<"ensure_postgres_version"/utf8>>, line => 406, value => _assert_fail, start => 11966, 'end' => 12006, pattern_start => 11977, pattern_end => 11996}) end, case gleam@result:'try'( gleam@bit_array:to_string(Version@2), fun gleam_stdlib:parse_int/1 ) of {error, _} -> eval:throw({postgres_version_has_invalid_format, Version@2}); {ok, Version@3} when Version@3 >= 160000 -> eval:return(nil); {ok, _} -> eval:throw(postgres_version_is_too_old) end end ). -file("src/squirrel/internal/database/postgres.gleam", 306). ?DOC(false). -spec main(list(squirrel@internal@query:untyped_query()), connection_options()) -> {ok, {list(squirrel@internal@query:typed_query()), list(squirrel@internal@error:error())}} | {error, squirrel@internal@error:error()}. main(Queries, Connection) -> {connection_options, Host, Port, User, Password, Database, Timeout_seconds} = Connection, gleam@result:'try'( begin _pipe = squirrel@internal@database@postgres_protocol:connect( Host, Port, Timeout_seconds * 1000 ), gleam@result:map_error( _pipe, fun(_capture) -> {pg_cannot_establish_tcp_connection, Host, Port, _capture} end ) end, fun(Db) -> Context = {context, Db, maps:new(), maps:new()}, Setup_script = begin eval:'try'( authenticate(User, Database, Password), fun(_) -> eval:'try'( ensure_postgres_version(), fun(_) -> eval:return(nil) end ) end ) end, {Context@1, Connection@1} = eval:step(Setup_script, Context), gleam@result:'try'( Connection@1, fun(_) -> _pipe@1 = gleam@list:map(Queries, fun infer_types/1), _pipe@2 = squirrel@internal@eval_extra:run_all( _pipe@1, Context@1 ), _pipe@3 = gleam@result:partition(_pipe@2), {ok, _pipe@3} end ) end ).