-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, <> ); [{some, Val} | Rest@1] -> case Elem_encode(Val) of {ok, Encoded} -> Len = erlang:byte_size(Encoded), encode_elements( Rest@1, Elem_encode, <> ); {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, <
>}; {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] ); <> -> 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).