Current section

Files

Jump to
squirrel src squirrel@internal@database@postgres.erl
Raw

src/squirrel@internal@database@postgres.erl

-module(squirrel@internal@database@postgres).
-compile([no_auto_import, nowarn_unused_vars, nowarn_unused_function, nowarn_nomatch]).
-export([main/1]).
-export_type([pg_type/0, context/0, nullability/0, plan/0, join_type/0, parent_relation/0]).
-type pg_type() :: {p_base, binary()} |
{p_array, pg_type()} |
{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()),
gleam@option:option(parent_relation()),
gleam@option:option(list(binary())),
gleam@option:option(list(plan()))}.
-type join_type() :: full | left | right | other.
-type parent_relation() :: inner | not_inner.
-spec pg_to_gleam_type(pg_type()) -> squirrel@internal@gleam:type().
pg_to_gleam_type(Type_) ->
case Type_ of
{p_array, Inner} ->
{list, pg_to_gleam_type(Inner)};
{p_option, Inner@1} ->
{option, pg_to_gleam_type(Inner@1)};
{p_base, Name} ->
case Name of
<<"bool"/utf8>> ->
bool;
<<"text"/utf8>> ->
string;
<<"char"/utf8>> ->
string;
<<"float4"/utf8>> ->
float;
<<"float8"/utf8>> ->
float;
<<"int2"/utf8>> ->
int;
<<"int4"/utf8>> ->
int;
<<"int8"/utf8>> ->
int;
_ ->
erlang:error(#{gleam_error => panic,
message => <<"TODO)) unsupported type"/utf8>>,
module => <<"squirrel/internal/database/postgres"/utf8>>,
function => <<"pg_to_gleam_type"/utf8>>,
line => 123})
end
end.
-spec error_fields_to_parse_error(
squirrel@internal@query:'query'(),
gleam@set:set(squirrel@internal@database@postgres_protocol:error_or_notice_field())
) -> squirrel@internal@error:error().
error_fields_to_parse_error(Query, Errors) ->
{Code@2, Message@2, Position@3, Hint@2} = (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@int:parse(Position@1) of
{ok, Position@2} ->
{Code, Message, {some, Position@2}, Hint};
{error, _} ->
Acc
end;
_ ->
Acc
end
end
)),
{cannot_parse_query, Query, Code@2, Message@2, Hint@2, Position@3}.
-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) ->
Nullables@2 = case {erlang:element(4, Plan),
erlang:element(2, Plan),
erlang:element(3, Plan)} of
{{some, Outputs}, {some, full}, _} ->
gleam@list:fold(
Outputs,
Nullables,
fun(Nullables@1, Output) ->
case gleam@dict:get(Query_outputs, Output) of
{ok, I} ->
gleam@set:insert(Nullables@1, I);
{error, _} ->
Nullables@1
end
end
);
{{some, Outputs}, _, {some, inner}} ->
gleam@list:fold(
Outputs,
Nullables,
fun(Nullables@1, Output) ->
case gleam@dict:get(Query_outputs, Output) of
{ok, I} ->
gleam@set:insert(Nullables@1, I);
{error, _} ->
Nullables@1
end
end
);
{_, _, _} ->
Nullables
end,
case {erlang:element(5, Plan), erlang:element(2, Plan)} of
{{some, Plans}, {some, left}} ->
gleam@list:fold(
Plans,
Nullables@2,
fun(Nullables@3, Plan@1) ->
do_nullables_from_plan(Plan@1, Query_outputs, Nullables@3)
end
);
{{some, Plans}, {some, right}} ->
gleam@list:fold(
Plans,
Nullables@2,
fun(Nullables@3, Plan@1) ->
do_nullables_from_plan(Plan@1, Query_outputs, Nullables@3)
end
);
{_, _} ->
Nullables@2
end.
-spec nullables_from_plan(plan()) -> gleam@set:set(integer()).
nullables_from_plan(Plan) ->
Outputs@1 = case erlang:element(4, Plan) of
{some, Outputs} ->
gleam@list:index_fold(
Outputs,
gleam@dict:new(),
fun gleam@dict:insert/3
);
none ->
gleam@dict:new()
end,
do_nullables_from_plan(Plan, Outputs@1, gleam@set:new()).
-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}} ->
{erlang:setelement(2, Context, Db@1), {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
).
-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,
{erlang:setelement(2, Context, Db@2), Result@1}
end
).
-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
).
-spec parameters_and_returns(squirrel@internal@query:'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(4, Query), []},
{fe_describe, prepared_statement, <<""/utf8>>},
fe_sync]
),
fun(_) -> eval:'try'('receive'(), fun(Msg) -> case Msg of
{be_error_response, Errors} ->
eval:throw(
error_fields_to_parse_error(Query, Errors)
);
be_parse_complete ->
eval:'try'(
'receive'(),
fun(Msg@1) ->
{be_parameter_description, Parameters} = case Msg@1 of
{be_parameter_description, _} -> Msg@1;
_assert_fail ->
erlang:error(
#{gleam_error => let_assert,
message => <<"Assertion pattern match failed"/utf8>>,
value => _assert_fail,
module => <<"squirrel/internal/database/postgres"/utf8>>,
function => <<"parameters_and_returns"/utf8>>,
line => 216}
)
end,
eval:'try'(
'receive'(),
fun(Msg@2) ->
{be_row_descriptions, Rows} = case Msg@2 of
{be_row_descriptions, _} -> Msg@2;
_assert_fail@1 ->
erlang:error(
#{gleam_error => let_assert,
message => <<"Assertion pattern match failed"/utf8>>,
value => _assert_fail@1,
module => <<"squirrel/internal/database/postgres"/utf8>>,
function => <<"parameters_and_returns"/utf8>>,
line => 218}
)
end,
eval:'try'(
'receive'(),
fun(Msg@3) ->
{be_ready_for_query, _} = case Msg@3 of
{be_ready_for_query, _} -> Msg@3;
_assert_fail@2 ->
erlang:error(
#{gleam_error => let_assert,
message => <<"Assertion pattern match failed"/utf8>>,
value => _assert_fail@2,
module => <<"squirrel/internal/database/postgres"/utf8>>,
function => <<"parameters_and_returns"/utf8>>,
line => 220}
)
end,
eval:return(
{Parameters, Rows}
)
end
)
end
)
end
);
_ ->
erlang:error(#{gleam_error => panic,
message => <<"parse complete: unexpected message sequence"/utf8>>,
module => <<"squirrel/internal/database/postgres"/utf8>>,
function => <<"parameters_and_returns"/utf8>>,
line => 223})
end end) end
).
-spec run_query(
binary(),
list(squirrel@internal@database@postgres_protocol:parameter_value()),
list(integer())
) -> eval:eval(list(bitstring()), squirrel@internal@error:error(), context()).
run_query(Query, Parameters, Parameters_object_ids) ->
eval:'try'(
send_all(
[{fe_parse, <<""/utf8>>, 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) ->
be_parse_complete = case Msg of
be_parse_complete -> Msg;
_assert_fail ->
erlang:error(#{gleam_error => let_assert,
message => <<"Assertion pattern match failed"/utf8>>,
value => _assert_fail,
module => <<"squirrel/internal/database/postgres"/utf8>>,
function => <<"run_query"/utf8>>,
line => 489})
end,
eval:'try'(
'receive'(),
fun(Msg@1) ->
be_bind_complete = case Msg@1 of
be_bind_complete -> Msg@1;
_assert_fail@1 ->
erlang:error(#{gleam_error => let_assert,
message => <<"Assertion pattern match failed"/utf8>>,
value => _assert_fail@1,
module => <<"squirrel/internal/database/postgres"/utf8>>,
function => <<"run_query"/utf8>>,
line => 491})
end,
eval:'try'(
'receive'(),
fun(Msg@2) ->
{be_message_data_row, Res} = case Msg@2 of
{be_message_data_row, _} -> Msg@2;
_assert_fail@2 ->
erlang:error(
#{gleam_error => let_assert,
message => <<"Assertion pattern match failed"/utf8>>,
value => _assert_fail@2,
module => <<"squirrel/internal/database/postgres"/utf8>>,
function => <<"run_query"/utf8>>,
line => 493}
)
end,
eval:'try'(
'receive'(),
fun(Msg@3) ->
{be_command_complete, _, _} = case Msg@3 of
{be_command_complete, _, _} -> Msg@3;
_assert_fail@3 ->
erlang:error(
#{gleam_error => let_assert,
message => <<"Assertion pattern match failed"/utf8>>,
value => _assert_fail@3,
module => <<"squirrel/internal/database/postgres"/utf8>>,
function => <<"run_query"/utf8>>,
line => 495}
)
end,
eval:'try'(
'receive'(),
fun(Msg@4) ->
be_close_complete = case Msg@4 of
be_close_complete -> Msg@4;
_assert_fail@4 ->
erlang:error(
#{gleam_error => let_assert,
message => <<"Assertion pattern match failed"/utf8>>,
value => _assert_fail@4,
module => <<"squirrel/internal/database/postgres"/utf8>>,
function => <<"run_query"/utf8>>,
line => 497}
)
end,
eval:'try'(
'receive'(),
fun(Msg@5) ->
be_close_complete = case Msg@5 of
be_close_complete -> Msg@5;
_assert_fail@5 ->
erlang:error(
#{gleam_error => let_assert,
message => <<"Assertion pattern match failed"/utf8>>,
value => _assert_fail@5,
module => <<"squirrel/internal/database/postgres"/utf8>>,
function => <<"run_query"/utf8>>,
line => 499}
)
end,
eval:'try'(
'receive'(),
fun(Msg@6) ->
{be_ready_for_query,
_} = case Msg@6 of
{be_ready_for_query,
_} -> Msg@6;
_assert_fail@6 ->
erlang:error(
#{gleam_error => let_assert,
message => <<"Assertion pattern match failed"/utf8>>,
value => _assert_fail@6,
module => <<"squirrel/internal/database/postgres"/utf8>>,
function => <<"run_query"/utf8>>,
line => 501}
)
end,
eval:return(
Res
)
end
)
end
)
end
)
end
)
end
)
end
)
end
)
end
).
-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).
-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).
-spec authenticate() -> eval:eval(nil, squirrel@internal@error:error(), context()).
authenticate() ->
Params = [{<<"user"/utf8>>, <<"giacomocavalieri"/utf8>>},
{<<"database"/utf8>>, <<"prova"/utf8>>}],
eval:'try'(
send({fe_startup_message, Params}),
fun(_) ->
eval:'try'(
'receive'(),
fun(Msg) ->
be_authentication_ok = case Msg of
be_authentication_ok -> Msg;
_assert_fail ->
erlang:error(#{gleam_error => let_assert,
message => <<"Assertion pattern match failed"/utf8>>,
value => _assert_fail,
module => <<"squirrel/internal/database/postgres"/utf8>>,
function => <<"authenticate"/utf8>>,
line => 157})
end,
eval:'try'(
wait_until_ready(),
fun(_) -> eval:return(nil) end
)
end
)
end
).
-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@dict: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 = erlang:setelement(
3,
Context@1,
Gleam_types@1
),
{New_context, {ok, Type_@1}}
end
end end
).
-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@dict: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 = erlang:setelement(
4,
Context@1,
Column_nullability@1
),
{New_context, {ok, Type_@1}}
end
end
end
).
-spec join_type_decoder(gleam@dynamic:dynamic_()) -> {ok, join_type()} |
{error, list(gleam@dynamic:decode_error())}.
join_type_decoder(Data) ->
gleam@result:map(gleam@dynamic:string(Data), fun(Data@1) -> case Data@1 of
<<"Full"/utf8>> ->
full;
<<"Left"/utf8>> ->
left;
<<"Right"/utf8>> ->
right;
_ ->
other
end end).
-spec parent_relation_decoder(gleam@dynamic:dynamic_()) -> {ok,
parent_relation()} |
{error, list(gleam@dynamic:decode_error())}.
parent_relation_decoder(Data) ->
gleam@result:map(gleam@dynamic:string(Data), fun(Data@1) -> case Data@1 of
<<"Inner"/utf8>> ->
inner;
_ ->
not_inner
end end).
-spec plan_decoder(gleam@dynamic:dynamic_()) -> {ok, plan()} |
{error, list(gleam@dynamic:decode_error())}.
plan_decoder(Data) ->
(gleam@dynamic:decode4(
fun(Field@0, Field@1, Field@2, Field@3) -> {plan, Field@0, Field@1, Field@2, Field@3} end,
gleam@dynamic:optional_field(
<<"Join Type"/utf8>>,
fun join_type_decoder/1
),
gleam@dynamic:optional_field(
<<"Parent Relationship"/utf8>>,
fun parent_relation_decoder/1
),
gleam@dynamic:optional_field(
<<"Output"/utf8>>,
gleam@dynamic:list(fun gleam@dynamic:string/1)
),
gleam@dynamic:optional_field(
<<"Plans"/utf8>>,
gleam@dynamic:list(fun plan_decoder/1)
)
))(Data).
-spec json_plans_decoder(gleam@dynamic:dynamic_()) -> {ok, list(plan())} |
{error, list(gleam@dynamic:decode_error())}.
json_plans_decoder(Data) ->
(gleam@dynamic:list(
gleam@dynamic:field(<<"Plan"/utf8>>, fun plan_decoder/1)
))(Data).
-spec query_plan(squirrel@internal@query:'query'(), integer()) -> eval:eval(plan(), squirrel@internal@error:error(), context()).
query_plan(Query, Parameters) ->
Query@1 = <<"explain (format json, verbose) "/utf8,
(erlang:element(4, Query))/binary>>,
Params = gleam@list:repeat(null, Parameters),
Run_query = run_query(Query@1, Params, []),
eval:'try'(
Run_query,
fun(Res) ->
[Plan] = case Res of
[_] -> Res;
_assert_fail ->
erlang:error(#{gleam_error => let_assert,
message => <<"Assertion pattern match failed"/utf8>>,
value => _assert_fail,
module => <<"squirrel/internal/database/postgres"/utf8>>,
function => <<"query_plan"/utf8>>,
line => 310})
end,
_assert_subject = gleam@json:decode_bits(
Plan,
fun json_plans_decoder/1
),
{ok, [Plan@1 | _]} = case _assert_subject of
{ok, [_ | _]} -> _assert_subject;
_assert_fail@1 ->
erlang:error(#{gleam_error => let_assert,
message => <<"Assertion pattern match failed"/utf8>>,
value => _assert_fail@1,
module => <<"squirrel/internal/database/postgres"/utf8>>,
function => <<"query_plan"/utf8>>,
line => 311})
end,
eval:return(Plan@1)
end
).
-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.
-spec find_gleam_type(integer()) -> eval:eval(squirrel@internal@gleam:type(), squirrel@internal@error:error(), context()).
find_gleam_type(Oid) ->
with_cached_gleam_type(
Oid,
fun() ->
Params = [{parameter, <<Oid:32>>}],
Run_query = begin
_pipe = <<"
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,
-- Tells us how to interpret the firs 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
from
pg_type as type
left join pg_type as elem on type.typelem = elem.oid
where
type.oid = $1
"/utf8>>,
run_query(_pipe, Params, [23])
end,
eval:'try'(
Run_query,
fun(Res) ->
[Name, Is_array] = case Res of
[_, _] -> Res;
_assert_fail ->
erlang:error(#{gleam_error => let_assert,
message => <<"Assertion pattern match failed"/utf8>>,
value => _assert_fail,
module => <<"squirrel/internal/database/postgres"/utf8>>,
function => <<"find_gleam_type"/utf8>>,
line => 282})
end,
_assert_subject = gleam@bit_array:to_string(Name),
{ok, Name@1} = case _assert_subject of
{ok, _} -> _assert_subject;
_assert_fail@1 ->
erlang:error(#{gleam_error => let_assert,
message => <<"Assertion pattern match failed"/utf8>>,
value => _assert_fail@1,
module => <<"squirrel/internal/database/postgres"/utf8>>,
function => <<"find_gleam_type"/utf8>>,
line => 287})
end,
Type_ = case bit_array_to_bool(Is_array) of
true ->
{p_array, {p_base, Name@1}};
false ->
{p_base, Name@1}
end,
eval:return(pg_to_gleam_type(Type_))
end
)
end
).
-spec resolve_parameters(list(integer())) -> eval:eval(list(squirrel@internal@gleam:type()), squirrel@internal@error:error(), context()).
resolve_parameters(Parameters) ->
squirrel@internal@eval_extra:try_map(
Parameters,
fun(Oid) -> find_gleam_type(Oid) end
).
-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, <<Table:32>>},
{parameter, <<Column:32>>}],
Run_query = begin
_pipe = <<"
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>>,
run_query(_pipe, Params, [23, 23])
end,
eval:'try'(
Run_query,
fun(Res) ->
[Has_non_null_constraint] = case Res of
[_] -> Res;
_assert_fail ->
erlang:error(#{gleam_error => let_assert,
message => <<"Assertion pattern match failed"/utf8>>,
value => _assert_fail,
module => <<"squirrel/internal/database/postgres"/utf8>>,
function => <<"column_nullability"/utf8>>,
line => 422})
end,
case bit_array_to_bool(Has_non_null_constraint) of
true ->
eval:return(not_nullable);
false ->
eval:return(nullable)
end
end
)
end
)
end
).
-spec resolve_returns(
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(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(Type_oid),
fun(Type_) ->
eval:'try'(
case gleam@string:ends_with(Name, <<"!"/utf8>>) of
true ->
eval:return(not_nullable);
false ->
case gleam@string:ends_with(Name, <<"?"/utf8>>) 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,
Field = {field,
squirrel@internal@gleam:to_function_name(Name),
Type_@1},
eval:return(Field)
end
)
end
)
end
).
-spec infer_types(squirrel@internal@query:'query'()) -> eval:eval(squirrel@internal@query:typed_query(), squirrel@internal@error:error(), context()).
infer_types(Query) ->
Action = parameters_and_returns(Query),
eval:'try'(
Action,
fun(_use0) ->
{Parameters, Returns} = _use0,
eval:'try'(
resolve_parameters(Parameters),
fun(Parameters@1) ->
eval:'try'(
query_plan(Query, erlang:length(Parameters@1)),
fun(Plan) ->
eval:'try'(
resolve_returns(
Returns,
nullables_from_plan(Plan)
),
fun(Returns@1) -> _pipe = Query,
_pipe@1 = squirrel@internal@query:add_types(
_pipe,
Parameters@1,
Returns@1
),
eval:return(_pipe@1) end
)
end
)
end
)
end
).
-spec main(list(squirrel@internal@query:'query'())) -> {ok,
list(squirrel@internal@query:typed_query())} |
{error, squirrel@internal@error:error()}.
main(Queries) ->
Script = (eval:'try'(
authenticate(),
fun(_) ->
squirrel@internal@eval_extra:try_map(
Queries,
fun(Query) -> infer_types(Query) end
)
end
)),
_pipe = Script,
eval:run(
_pipe,
{context,
squirrel@internal@database@postgres_protocol:connect(
<<"localhost"/utf8>>,
5432,
1000
),
gleam@dict:new(),
gleam@dict:new()}
).