Current section
Files
Jump to
Current section
Files
src/typeid.erl
-module(typeid).
-compile([no_auto_import, nowarn_unused_vars, nowarn_unused_function, nowarn_nomatch]).
-define(FILEPATH, "src/typeid.gleam").
-export([prefix/1, suffix/1, to_string/1, uuid/1, from_uuid/2, new/1, parse/1, decode/1]).
-export_type([type_id/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.
-opaque type_id(ELF) :: {type_id, binary(), binary()} | {gleam_phantom, ELF}.
-file("src/typeid.gleam", 134).
?DOC(
" Returns the prefix of the TypeId.\n"
"\n"
" ### Usage\n"
" ```gleam\n"
" let assert Ok(id) = new(\"user\")\n"
" prefix(id) // \"user\"\n"
" ```\n"
).
-spec prefix(type_id(any())) -> binary().
prefix(Typeid) ->
erlang:element(2, Typeid).
-file("src/typeid.gleam", 145).
?DOC(
" Returns the suffix of the TypeId.\n"
"\n"
" ### Usage\n"
" ```gleam\n"
" let assert Ok(id) = new(\"user\")\n"
" suffix(id) // \"01h455vb4pex5vsknk084sn02q\"\n"
" ```\n"
).
-spec suffix(type_id(any())) -> binary().
suffix(Typeid) ->
erlang:element(3, Typeid).
-file("src/typeid.gleam", 159).
?DOC(
" Returns the string representation of a TypeId.\n"
"\n"
" ### Usage\n"
" ```gleam\n"
" let assert Ok(id) = new(\"user\")\n"
" to_string(id) // \"user_01h455vb4pex5vsknk084sn02q\"\n"
"\n"
" let assert Ok(id) = new(\"\")\n"
" to_string(id) // \"01h455vb4pex5vsknk084sn02q\"\n"
" ```\n"
).
-spec to_string(type_id(any())) -> binary().
to_string(Typeid) ->
case erlang:element(2, Typeid) of
<<""/utf8>> ->
erlang:element(3, Typeid);
_ ->
<<<<(erlang:element(2, Typeid))/binary, "_"/utf8>>/binary,
(erlang:element(3, Typeid))/binary>>
end.
-file("src/typeid.gleam", 166).
-spec prefix_suffix(binary()) -> {ok, {binary(), binary()}} | {error, nil}.
prefix_suffix(Raw_typeid) ->
_pipe = gleam@string:reverse(Raw_typeid),
_pipe@1 = gleam@string:split_once(_pipe, <<"_"/utf8>>),
gleam@result:'try'(
_pipe@1,
fun(Sp) ->
{Xiffus, Xiferp} = Sp,
Prefix = gleam@string:reverse(Xiferp),
Suffix = gleam@string:reverse(Xiffus),
{ok, {Prefix, Suffix}}
end
).
-file("src/typeid.gleam", 206).
-spec index_to_alphabet(integer()) -> binary().
index_to_alphabet(Index) ->
case Index of
0 ->
<<"0"/utf8>>;
1 ->
<<"1"/utf8>>;
2 ->
<<"2"/utf8>>;
3 ->
<<"3"/utf8>>;
4 ->
<<"4"/utf8>>;
5 ->
<<"5"/utf8>>;
6 ->
<<"6"/utf8>>;
7 ->
<<"7"/utf8>>;
8 ->
<<"8"/utf8>>;
9 ->
<<"9"/utf8>>;
10 ->
<<"a"/utf8>>;
11 ->
<<"b"/utf8>>;
12 ->
<<"c"/utf8>>;
13 ->
<<"d"/utf8>>;
14 ->
<<"e"/utf8>>;
15 ->
<<"f"/utf8>>;
16 ->
<<"g"/utf8>>;
17 ->
<<"h"/utf8>>;
18 ->
<<"j"/utf8>>;
19 ->
<<"k"/utf8>>;
20 ->
<<"m"/utf8>>;
21 ->
<<"n"/utf8>>;
22 ->
<<"p"/utf8>>;
23 ->
<<"q"/utf8>>;
24 ->
<<"r"/utf8>>;
25 ->
<<"s"/utf8>>;
26 ->
<<"t"/utf8>>;
27 ->
<<"v"/utf8>>;
28 ->
<<"w"/utf8>>;
29 ->
<<"x"/utf8>>;
30 ->
<<"y"/utf8>>;
31 ->
<<"z"/utf8>>;
_ ->
<<"0"/utf8>>
end.
-file("src/typeid.gleam", 184).
?DOC(" Recursively grabs 5 bits and uses them as index in the alphabet and concatinate them to a string.\n").
-spec encode_bits_base32(bitstring(), binary()) -> binary().
encode_bits_base32(Binary, Acc) ->
case Binary of
<<Index:5/unsigned, Rest/bitstring>> ->
encode_bits_base32(
Rest,
<<Acc/binary, (index_to_alphabet(Index))/binary>>
);
_ ->
Acc
end.
-file("src/typeid.gleam", 178).
-spec encode_base32(bitstring()) -> binary().
encode_base32(Bits) ->
encode_bits_base32(<<0:2, Bits:128/bitstring>>, <<""/utf8>>).
-file("src/typeid.gleam", 244).
-spec alphabet_to_index(binary()) -> integer().
alphabet_to_index(Char) ->
case Char of
<<"0"/utf8>> ->
0;
<<"1"/utf8>> ->
1;
<<"2"/utf8>> ->
2;
<<"3"/utf8>> ->
3;
<<"4"/utf8>> ->
4;
<<"5"/utf8>> ->
5;
<<"6"/utf8>> ->
6;
<<"7"/utf8>> ->
7;
<<"8"/utf8>> ->
8;
<<"9"/utf8>> ->
9;
<<"a"/utf8>> ->
10;
<<"b"/utf8>> ->
11;
<<"c"/utf8>> ->
12;
<<"d"/utf8>> ->
13;
<<"e"/utf8>> ->
14;
<<"f"/utf8>> ->
15;
<<"g"/utf8>> ->
16;
<<"h"/utf8>> ->
17;
<<"j"/utf8>> ->
18;
<<"k"/utf8>> ->
19;
<<"m"/utf8>> ->
20;
<<"n"/utf8>> ->
21;
<<"p"/utf8>> ->
22;
<<"q"/utf8>> ->
23;
<<"r"/utf8>> ->
24;
<<"s"/utf8>> ->
25;
<<"t"/utf8>> ->
26;
<<"v"/utf8>> ->
27;
<<"w"/utf8>> ->
28;
<<"x"/utf8>> ->
29;
<<"y"/utf8>> ->
30;
<<"z"/utf8>> ->
31;
_ ->
0
end.
-file("src/typeid.gleam", 192).
-spec decode_base32(binary()) -> {ok, bitstring()} | {error, nil}.
decode_base32(Enc_suffix) ->
Bits = begin
_pipe = gleam@string:to_graphemes(Enc_suffix),
gleam@list:fold(
_pipe,
<<>>,
fun(Acc, C) ->
Index = alphabet_to_index(C),
<<Acc/bitstring, Index:5>>
end
)
end,
case Bits of
<<0:2, Res:128/bitstring>> ->
{ok, Res};
_ ->
{error, nil}
end.
-file("src/typeid.gleam", 122).
?DOC(
" Returns the UUID string representation of the TypeId suffix.\n"
"\n"
" ### Usage\n"
" ```gleam\n"
" let assert Ok(id) = new(\"user\")\n"
" uuid(id) // \"0110c853-1d09-52d8-d73e-1194e95b5f19\"\n"
" ```\n"
).
-spec uuid(type_id(any())) -> binary().
uuid(Typeid) ->
Bits@1 = case decode_base32(erlang:element(3, Typeid)) of
{ok, Bits} -> Bits;
_assert_fail ->
erlang:error(#{gleam_error => let_assert,
message => <<"Pattern match failed, no pattern matched the value."/utf8>>,
file => <<?FILEPATH/utf8>>,
module => <<"typeid"/utf8>>,
function => <<"uuid"/utf8>>,
line => 123,
value => _assert_fail,
start => 3394,
'end' => 3444,
pattern_start => 3405,
pattern_end => 3413})
end,
typeid@uuid:to_string(Bits@1).
-file("src/typeid.gleam", 39).
?DOC(
" Generate a TypeID using the supplied prefix and UUID.\n"
"\n"
" ### Usage\n"
" ```gleam\n"
" let assert Ok(id) = from_uuid(\"user\", \"018fcec0-b44b-7ce2-b187-2f08349beab9\")\n"
" ```\n"
).
-spec from_uuid(binary(), binary()) -> {ok, type_id(any())} | {error, binary()}.
from_uuid(Prefix, Uuid) ->
Re@1 = case gleam@regexp:from_string(
<<"^([a-z]([a-z_]{0,61}[a-z])?)?$"/utf8>>
) of
{ok, Re} -> Re;
_assert_fail ->
erlang:error(#{gleam_error => let_assert,
message => <<"Pattern match failed, no pattern matched the value."/utf8>>,
file => <<?FILEPATH/utf8>>,
module => <<"typeid"/utf8>>,
function => <<"from_uuid"/utf8>>,
line => 43,
value => _assert_fail,
start => 1145,
'end' => 1197,
pattern_start => 1156,
pattern_end => 1162})
end,
case gleam@regexp:check(Re@1, Prefix) of
true ->
case typeid@uuid:from_string(Uuid) of
{ok, Uuid@1} ->
Suffix = encode_base32(Uuid@1),
_pipe = {type_id, Prefix, Suffix},
{ok, _pipe};
{error, _} ->
{error, <<"Invalid UUID"/utf8>>}
end;
false ->
_pipe@1 = <<"Prefix must contain at most 63 characters and only lowercase alphabetic ASCII characters [a-z], or an underscore."/utf8>>,
{error, _pipe@1}
end.
-file("src/typeid.gleam", 29).
?DOC(
" Create a new TypeId with the given prefix.\n"
" Prefix must be a string containing at most 63 characters and only lowercase\n"
" alphabetic ASCII characters [a-z], or an underscore.\n"
" The prefix may also be empty.\n"
"\n"
" ### Usage\n"
" ```gleam\n"
" let assert Ok(id) = new(\"user\")\n"
" ```\n"
).
-spec new(binary()) -> {ok, type_id(any())} | {error, binary()}.
new(Prefix) ->
from_uuid(Prefix, typeid@uuid:v7()).
-file("src/typeid.gleam", 69).
?DOC(
" Parse a TypeId from a string.\n"
" \n"
" ### Usage\n"
" ```gleam\n"
" let assert Ok(id) = parse(\"user_01h455vb4pex5vsknk084sn02q\")\n"
" ```\n"
).
-spec parse(binary()) -> {ok, type_id(any())} | {error, binary()}.
parse(Raw_typeid) ->
Rs@1 = case gleam@regexp:from_string(
<<"^[01234567][0123456789abcdefghjkmnpqrstvwxyz]{25}$"/utf8>>
) of
{ok, Rs} -> Rs;
_assert_fail ->
erlang:error(#{gleam_error => let_assert,
message => <<"Pattern match failed, no pattern matched the value."/utf8>>,
file => <<?FILEPATH/utf8>>,
module => <<"typeid"/utf8>>,
function => <<"parse"/utf8>>,
line => 70,
value => _assert_fail,
start => 1828,
'end' => 1880,
pattern_start => 1839,
pattern_end => 1845})
end,
case prefix_suffix(Raw_typeid) of
{ok, {Prefix, Suffix}} when Prefix =/= <<""/utf8>> ->
Rp@1 = case gleam@regexp:from_string(
<<"^([a-z]([a-z_]{0,61}[a-z])?)?$"/utf8>>
) of
{ok, Rp} -> Rp;
_assert_fail@1 ->
erlang:error(#{gleam_error => let_assert,
message => <<"Pattern match failed, no pattern matched the value."/utf8>>,
file => <<?FILEPATH/utf8>>,
module => <<"typeid"/utf8>>,
function => <<"parse"/utf8>>,
line => 74,
value => _assert_fail@1,
start => 1970,
'end' => 2022,
pattern_start => 1981,
pattern_end => 1987})
end,
gleam@bool:guard(
not gleam@regexp:check(Rp@1, Prefix),
{error, <<"Prefix is malformed"/utf8>>},
fun() ->
gleam@bool:guard(
not gleam@regexp:check(Rs@1, Suffix),
{error, <<"Suffix is malformed"/utf8>>},
fun() -> _pipe = {type_id, Prefix, Suffix},
{ok, _pipe} end
)
end
);
_ ->
gleam@bool:guard(
not gleam@regexp:check(Rs@1, Raw_typeid),
{error, <<"Suffix is malformed"/utf8>>},
fun() -> _pipe@1 = {type_id, <<""/utf8>>, Raw_typeid},
{ok, _pipe@1} end
)
end.
-file("src/typeid.gleam", 104).
?DOC(
" TypeId decoder for use in Gleam's `decode` module.\n"
" When decoding the type(prefix) is known, which is why this function takes\n"
" the prefix as an argument to verify the prefix of the TypeId.\n"
"\n"
" ### Usage\n"
" ```gleam\n"
" let decoder = {\n"
" use id <- decode.field(\"id\", typeid.decode(\"user\"))\n"
" use name <- decode.field(\"name\", decode.string)\n"
" decode.success(User(id:, name:))\n"
" }\n"
" ```\n"
).
-spec decode(binary()) -> gleam@dynamic@decode:decoder(type_id(any())).
decode(Kind) ->
_pipe = {decoder, fun gleam@dynamic@decode:decode_string/1},
gleam@dynamic@decode:then(
_pipe,
fun(Id) -> case {prefix_suffix(Id), parse(Id)} of
{{ok, {Prefix, _}}, {ok, Typeid}} when Prefix =:= Kind ->
gleam@dynamic@decode:success(Typeid);
{_, _} ->
gleam@dynamic@decode:failure(
{type_id, <<""/utf8>>, <<""/utf8>>},
<<"TypeId(a)"/utf8>>
)
end end
).