Current section
Files
Jump to
Current section
Files
src/postgleam@codec@array.erl
-module(postgleam@codec@array).
-compile([no_auto_import, nowarn_unused_vars, nowarn_unused_function, nowarn_nomatch, inline]).
-define(FILEPATH, "src/postgleam/codec/array.gleam").
-export([array_oid_map/0, build_array_codec/2, register_arrays/1]).
-if(?OTP_RELEASE >= 27).
-define(MODULEDOC(Str), -moduledoc(Str)).
-define(DOC(Str), -doc(Str)).
-else.
-define(MODULEDOC(Str), -compile([])).
-define(DOC(Str), -compile([])).
-endif.
-file("src/postgleam/codec/array.gleam", 31).
?DOC(" Hardcoded array OID -> element OID mapping for common types\n").
-spec array_oid_map() -> list({integer(), integer()}).
array_oid_map() ->
[{1000, 16},
{1005, 21},
{1007, 23},
{1016, 20},
{1021, 700},
{1022, 701},
{1009, 25},
{1015, 1043},
{1001, 17},
{2951, 2950},
{199, 114},
{3807, 3802},
{1231, 1700},
{1182, 1082},
{1183, 1083},
{1270, 1266},
{1115, 1114},
{1185, 1184},
{1187, 1186},
{1028, 26},
{1003, 19},
{1041, 869},
{1040, 829},
{1017, 600}].
-file("src/postgleam/codec/array.gleam", 120).
-spec encode_elements(
list(gleam@option:option(postgleam@value:value())),
fun((postgleam@value:value()) -> {ok, bitstring()} | {error, binary()}),
bitstring()
) -> {ok, bitstring()} | {error, binary()}.
encode_elements(Elements, Elem_encode, Acc) ->
case Elements of
[] ->
{ok, Acc};
[none | Rest] ->
encode_elements(
Rest,
Elem_encode,
<<Acc/bitstring, 255, 255, 255, 255>>
);
[{some, Val} | Rest@1] ->
case Elem_encode(Val) of
{ok, Encoded} ->
Len = erlang:byte_size(Encoded),
encode_elements(
Rest@1,
Elem_encode,
<<Acc/bitstring, Len:32/big, Encoded/bitstring>>
);
{error, E} ->
{error,
<<"array codec: element encode failed: "/utf8,
E/binary>>}
end
end.
-file("src/postgleam/codec/array.gleam", 87).
-spec encode_array(
postgleam@value:value(),
integer(),
fun((postgleam@value:value()) -> {ok, bitstring()} | {error, binary()})
) -> {ok, bitstring()} | {error, binary()}.
encode_array(Val, Elem_oid, Elem_encode) ->
case Val of
{array, Elements} ->
Len = erlang:length(Elements),
case Len of
0 ->
{ok, <<0:32/big, 0:32/big, Elem_oid:32/big>>};
_ ->
Has_null = case gleam@list:any(
Elements,
fun(E) -> E =:= none end
) of
true ->
1;
false ->
0
end,
Header = <<1:32/big,
Has_null:32/big,
Elem_oid:32/big,
Len:32/big,
1:32/big>>,
case encode_elements(Elements, Elem_encode, <<>>) of
{ok, Body} ->
{ok, <<Header/bitstring, Body/bitstring>>};
{error, E@1} ->
{error, E@1}
end
end;
_ ->
{error, <<"array codec: expected Array value"/utf8>>}
end.
-file("src/postgleam/codec/array.gleam", 164).
-spec decode_elements(
bitstring(),
integer(),
fun((bitstring()) -> {ok, postgleam@value:value()} | {error, binary()}),
list(gleam@option:option(postgleam@value:value()))
) -> {ok, list(gleam@option:option(postgleam@value:value()))} |
{error, binary()}.
decode_elements(Data, Remaining, Elem_decode, Acc) ->
case Remaining of
0 ->
{ok, Acc};
_ ->
case Data of
<<-1:32/big-signed, Rest/bitstring>> ->
decode_elements(
Rest,
Remaining - 1,
Elem_decode,
[none | Acc]
);
<<Len:32/big, Elem_data:Len/binary, Rest@1/bitstring>> ->
case Elem_decode(Elem_data) of
{ok, Val} ->
decode_elements(
Rest@1,
Remaining - 1,
Elem_decode,
[{some, Val} | Acc]
);
{error, E} ->
{error,
<<"array codec: element decode failed: "/utf8,
E/binary>>}
end;
_ ->
{error,
<<"array codec: unexpected end of array data"/utf8>>}
end
end.
-file("src/postgleam/codec/array.gleam", 146).
-spec decode_array(
bitstring(),
fun((bitstring()) -> {ok, postgleam@value:value()} | {error, binary()})
) -> {ok, postgleam@value:value()} | {error, binary()}.
decode_array(Data, Elem_decode) ->
case Data of
<<0:32/big, _:32/big, _:32/big>> ->
{ok, {array, []}};
<<1:32/big,
_:32/big,
_:32/big,
Length:32/big,
_:32/big,
Rest/bitstring>> ->
case decode_elements(Rest, Length, Elem_decode, []) of
{ok, Elements} ->
{ok, {array, lists:reverse(Elements)}};
{error, E} ->
{error, E}
end;
_ ->
{error, <<"array codec: unsupported array format"/utf8>>}
end.
-file("src/postgleam/codec/array.gleam", 17).
?DOC(
" Build an array codec that wraps an element codec.\n"
" The element codec is captured in closures for encode/decode.\n"
).
-spec build_array_codec(postgleam@codec:codec(), integer()) -> postgleam@codec:codec().
build_array_codec(Element_codec, Array_oid) ->
Elem_oid = erlang:element(3, Element_codec),
Elem_encode = erlang:element(5, Element_codec),
Elem_decode = erlang:element(6, Element_codec),
{codec,
<<"array"/utf8>>,
Array_oid,
binary,
fun(Val) -> encode_array(Val, Elem_oid, Elem_encode) end,
fun(Data) -> decode_array(Data, Elem_decode) end}.
-file("src/postgleam/codec/array.gleam", 66).
-spec register_arrays_loop(
list({integer(), integer()}),
gleam@dict:dict(integer(), postgleam@codec:codec())
) -> gleam@dict:dict(integer(), postgleam@codec:codec()).
register_arrays_loop(Mappings, Reg) ->
case Mappings of
[] ->
Reg;
[{Array_oid, Elem_oid} | Rest] ->
Reg@1 = case postgleam@codec@registry:lookup(Reg, Elem_oid) of
{ok, Elem_codec} ->
Array_codec = build_array_codec(Elem_codec, Array_oid),
maps:put(Array_oid, Array_codec, Reg);
{error, _} ->
Reg
end,
register_arrays_loop(Rest, Reg@1)
end.
-file("src/postgleam/codec/array.gleam", 62).
?DOC(
" Register array codecs into an existing registry.\n"
" Looks up each element codec from the base registry, builds an array codec.\n"
).
-spec register_arrays(gleam@dict:dict(integer(), postgleam@codec:codec())) -> gleam@dict:dict(integer(), postgleam@codec:codec()).
register_arrays(Base) ->
register_arrays_loop(array_oid_map(), Base).