View Source LibEcto.Ksuid (lib_ecto v0.3.10)
ksuid is a zero dependency Elixir library for generating and parsing KSUIDs. Read more about ksuid here
ksuid stands for K-Sortable Unique Identifier. It's a way to generate globally unique IDs which are partially chronologically sortable.
How To
iex> LibEcto.Ksuid.generate()
"0p9kxW1vWavpdq7VSgbv8piY0nr"
iex> LibEcto.Ksuid.parse("0p9kxW1vWavpdq7VSgbv8piY0nr")
{
:ok,
%DateTime{calendar: Calendar.ISO, day: 9, hour: 14, microsecond: {0, 0},
minute: 52, month: 6, second: 34, std_offset: 0, time_zone: "Etc/UTC",
utc_offset: 0, year: 2017, zone_abbr: "UTC"},
<<166, 90, 80, 117, 89, 88, 196, 168, 113, 163, 157, 217, 224, 51, 151, 227>>
}
Example Ecto Usage
Ecto Type
defmodule LibEcto.KsuidType do
@moduledoc """
types for ksuid
uses string/varchar as storage type.
"""
@behaviour Ecto.Type
alias LibEcto.Ksuid
def type, do: :string
def cast(ksuid) when is_binary(ksuid), do: {:ok, ksuid}
def cast(_), do: :error
@doc """
Same as `cast/1` but raises `Ecto.CastError` on invalid arguments.
"""
def cast!(value) do
case cast(value) do
{:ok, ksuid} -> ksuid
:error -> raise Ecto.CastError, type: __MODULE__, value: value
end
end
def load(ksuid), do: {:ok, ksuid}
def dump(binary) when is_binary(binary), do: {:ok, binary}
def dump(_), do: :error
# Callback invoked by autogenerate fields - this is all that really matters
# just passing around the binary otherwise.
@doc false
def autogenerate, do: Ksuid.generate()
end
Usage in a Schema
:inserted_at
is a virtual field that can be derived/loaded from the autogenerated :id
defmodule TestSchema do
use Ecto.Schema
@primary_key {:id, KsuidType, autogenerate: true}
schema "test" do
field :name, :string
field :inserted_at, :utc_datetime, virtual: true
end
def inserted_at(%TestSchema{id: ksuid} = row) do
{:ok, time_stamp, _} = LibEcto.Ksuid.parse(ksuid)
%TestSchema{row | inserted_at: time_stamp}
end
end
Migration
Create :id
as :bytea
, and primary key - similary to usage with :binary_id
def change do
create table(:test, primary_key: false) do
add :id, :string, primary_key: true, size: 27
add :name, :text
end
end
Attention!!!!
Some databases(like MySQL) have a default case-insensitive comparison for binary. If you use ksuid as the primary key and need to compare or sort ids, you need to use the SQL binary() function.
query = from t in TestSchema, where: fragment("binary(?)", t.id) > ^id
repo.all(query, order_by: [desc: fragment("binary(?)", t.id)])
Summary
Functions
This method returns a 20 byte Ksuid which has 4 bytes as timestamp and 16 bytes of crypto string bytes.
Types
@type t() :: binary()
A Ksuid is a unique identifier that is made up of a timestamp and a random
Functions
@spec generate(non_neg_integer()) :: binary()
This method returns a 20 byte Ksuid which has 4 bytes as timestamp and 16 bytes of crypto string bytes.
Examples
iex> Ksuid.generate()
"0KZi94b2fnVzpGi60FoZgXIvUtYy"
@spec parse(binary()) :: {:ok, NaiveDateTime.t(), binary()} | {:error, any()}