2023-06-29 15:20:23 -04:00
|
|
|
defmodule TypeID do
|
|
|
|
@moduledoc """
|
|
|
|
Documentation for `TypeID`.
|
|
|
|
"""
|
|
|
|
|
2023-06-29 17:23:05 -04:00
|
|
|
alias TypeID.Base32
|
2023-06-29 15:20:23 -04:00
|
|
|
|
2023-06-29 17:23:05 -04:00
|
|
|
@enforce_keys [:prefix, :suffix]
|
|
|
|
defstruct @enforce_keys
|
2023-06-29 15:20:23 -04:00
|
|
|
|
2023-06-29 17:23:05 -04:00
|
|
|
@opaque t() :: %__MODULE__{
|
|
|
|
prefix: String.t(),
|
|
|
|
suffix: String.t()
|
|
|
|
}
|
2023-06-29 15:20:23 -04:00
|
|
|
|
2023-06-29 17:23:05 -04:00
|
|
|
@spec new(prefix :: String.t()) :: t()
|
|
|
|
def new(prefix) do
|
|
|
|
suffix =
|
|
|
|
Uniq.UUID.uuid7(:raw)
|
|
|
|
|> Base32.encode()
|
|
|
|
|
|
|
|
%__MODULE__{prefix: prefix, suffix: suffix}
|
|
|
|
end
|
|
|
|
|
|
|
|
@spec type(tid :: t()) :: String.t()
|
|
|
|
def type(%__MODULE__{prefix: prefix}) do
|
|
|
|
prefix
|
|
|
|
end
|
|
|
|
|
|
|
|
@spec suffix(tid :: t()) :: String.t()
|
|
|
|
def suffix(%__MODULE__{suffix: suffix}) do
|
|
|
|
suffix
|
|
|
|
end
|
|
|
|
|
|
|
|
@spec to_string(tid :: t()) :: String.t()
|
|
|
|
def to_string(%__MODULE__{prefix: prefix, suffix: suffix}) do
|
|
|
|
prefix <> "_" <> suffix
|
|
|
|
end
|
|
|
|
|
|
|
|
@spec uuid_bytes(tid :: t()) :: binary()
|
|
|
|
def uuid_bytes(%__MODULE__{suffix: suffix}) do
|
|
|
|
Base32.decode!(suffix)
|
|
|
|
end
|
|
|
|
|
|
|
|
@spec uuid(tid :: t()) :: String.t()
|
|
|
|
def uuid(%__MODULE__{suffix: suffix}) do
|
|
|
|
suffix
|
|
|
|
|> Base32.decode!()
|
|
|
|
|> Uniq.UUID.to_string(:default)
|
|
|
|
end
|
|
|
|
|
|
|
|
@spec from_string!(String.t()) :: t() | no_return()
|
|
|
|
def from_string!(str) do
|
|
|
|
[prefix, suffix] = String.split(str, "_")
|
|
|
|
from!(prefix, suffix)
|
|
|
|
end
|
|
|
|
|
|
|
|
@spec from!(prefix :: String.t(), suffix :: String.t()) :: t() | no_return()
|
|
|
|
def from!(prefix, suffix) do
|
|
|
|
validate_prefix!(prefix)
|
|
|
|
validate_suffix!(suffix)
|
|
|
|
|
|
|
|
%__MODULE__{prefix: prefix, suffix: suffix}
|
|
|
|
end
|
|
|
|
|
|
|
|
@spec from(prefix :: String.t(), suffix :: String.t()) :: {:ok, t()} | :error
|
|
|
|
def from(prefix, suffix) do
|
|
|
|
{:ok, from!(prefix, suffix)}
|
|
|
|
rescue
|
|
|
|
ArgumentError -> :error
|
|
|
|
end
|
|
|
|
|
|
|
|
@spec from_string!(String.t()) :: {:ok, t()} | :error
|
|
|
|
def from_string(str) do
|
|
|
|
{:ok, from_string!(str)}
|
|
|
|
rescue
|
|
|
|
ArgumentError -> :error
|
|
|
|
end
|
|
|
|
|
|
|
|
@spec from_uuid!(prefix :: String.t(), uuid :: String.t()) :: t() | no_return()
|
|
|
|
def from_uuid!(prefix, uuid) do
|
|
|
|
{:ok, %Uniq.UUID{bytes: uuid_bytes, version: 7}} = Uniq.UUID.parse(uuid)
|
|
|
|
from_uuid_bytes!(prefix, uuid_bytes)
|
|
|
|
end
|
|
|
|
|
|
|
|
@spec from_uuid_bytes!(prefix :: String.t(), uuid_bytes :: binary()) :: t() | no_return()
|
|
|
|
def from_uuid_bytes!(prefix, <<uuid_bytes::binary-size(16)>>) do
|
|
|
|
suffix = Base32.encode(uuid_bytes)
|
|
|
|
from!(prefix, suffix)
|
|
|
|
end
|
|
|
|
|
|
|
|
@spec from_uuid(prefix :: String.t(), uuid :: String.t()) :: {:ok, t()} | :error
|
|
|
|
def from_uuid(prefix, uuid) do
|
|
|
|
{:ok, from_uuid!(prefix, uuid)}
|
|
|
|
rescue
|
|
|
|
ArgumentError -> :error
|
|
|
|
end
|
|
|
|
|
|
|
|
@spec from_uuid_bytes(prefix :: String.t(), uuid_bytes :: binary()) :: {:ok, t()} | :error
|
|
|
|
def from_uuid_bytes(prefix, uuid_bytes) do
|
|
|
|
{:ok, from_uuid_bytes!(prefix, uuid_bytes)}
|
|
|
|
rescue
|
|
|
|
ArgumentError -> :error
|
|
|
|
end
|
|
|
|
|
|
|
|
defp validate_prefix!(prefix) do
|
2023-06-30 06:03:07 -04:00
|
|
|
unless prefix =~ ~r/^[a-z]{0,63}$/ do
|
2023-06-29 17:23:05 -04:00
|
|
|
raise ArgumentError, "invalid prefix: #{prefix}. prefix should match [a-z]{0,63}"
|
|
|
|
end
|
|
|
|
|
|
|
|
:ok
|
|
|
|
end
|
|
|
|
|
|
|
|
defp validate_suffix!(suffix) do
|
|
|
|
Base32.decode!(suffix)
|
|
|
|
|
|
|
|
:ok
|
|
|
|
end
|
|
|
|
end
|
|
|
|
|
|
|
|
defimpl Inspect, for: TypeID do
|
|
|
|
import Inspect.Algebra
|
|
|
|
|
|
|
|
def inspect(tid, _opts) do
|
|
|
|
concat(["TypeID.from_string!(\"", tid.prefix, "_", tid.suffix, "\")"])
|
2023-06-29 15:20:23 -04:00
|
|
|
end
|
|
|
|
end
|