# Typeid

[![hex.pm version](https://img.shields.io/hexpm/v/elixir_typeid.svg)](https://hex.pm/packages/elixir_typeid)
[![Hex Docs](https://img.shields.io/badge/hex-docs-lightgreen.svg)](https://hexdocs.pm/elixir_typeid)

An Elixir implementation of [TypeID](https://github.com/jetify-com/typeid).

TypeIDs are a modern, type-safe, globally unique identifier based on the upcoming
UUIDv7 standard. They provide a ton of nice properties that make them a great choice
as the primary identifiers for your data in a database, APIs, and distributed systems.
Read more about TypeIDs in the [specification](https://github.com/jetify-com/typeid/tree/main/spec).

## Installation

Requires Elixir 1.14 or later.

```elixir
def deps do
  [
    {:elixir_typeid, "~> 0.3"}
  ]
end
```

## Intro

- Covers the [formal TypeID specification test cases](https://github.com/jetify-com/typeid/tree/main/spec#validating-implementations).
- Implements `Ecto.ParameterizedType` for optional Ecto schema integration.
- Implements the built-in `JSON.Encoder` protocol when it is available.
- Implements `Jason.Encoder` for optional Jason encoding.

The Ecto and Jason extensions are generated when their optional dependencies are available while `elixir_typeid` is compiled. If either dependency is added later, recompile this library. The built-in `JSON.Encoder` implementation is generated on Elixir releases that provide the `JSON` module.

## Usage

```elixir
iex> {:ok, typeid} = Typeid.new("user")
{:ok, #Typeid<"user_01hz6wxrw2ecmtwaqhnnpr275f">}
iex> "#{typeid}"
"user_01hz6wxrw2ecmtwaqhnnpr275f"
iex> Typeid.uuid(typeid)
{:ok, #UUIDv7<018fcdce-e382-7329-ae2a-f1ad6d811caf>}
iex> Typeid.parse("user_01hz6wxrw2ecmtwaqhnnpr275f")
{:ok, #Typeid<"user_01hz6wxrw2ecmtwaqhnnpr275f">}
iex> Typeid.valid?(typeid)
true
```

### Use with Ecto

In usual we use TypeID to generate the primary key with Ecto schema, define `Typeid` type within `@primary_key`:

```elixir

  defmodule User do
    use Ecto.Schema

    @primary_key {:id, Typeid, autogenerate: true, type: "user"}
    schema "user" do
      field(:name, :string)
    end
  end

```

or define `Typeid` type in a primary key field of a schema:

```elixir

  defmodule User do
    use Ecto.Schema

    @primary_key false
    schema "user" do
      field(:user_id, Typeid, autogenerate: true, primary_key: true, type: "user")
      field(:name, :string)
    end
  end
```

If `type: "user"` is not set, TypeID uses an unprefixed value (`prefix: nil`). The configured `type` must be `nil`, `""`, or a valid TypeID prefix. Ecto validates the complete TypeID and requires a configured prefix to match exactly during casting, loading, and dumping. Ecto integration requires Ecto `~> 3.5`.

### Use with Built-in JSON Encoding

When the built-in `JSON` module is available, we can encode a `Typeid` struct as a JSON string:

```elixir
iex> {:ok, typeid} = Typeid.new("user")
iex> JSON.encode!(typeid)
"\"user_01hz6wxrw2ecmtwaqhnnpr275f\""
```

### Use with Jason Encoding

We can simply encode a `Typeid` struct with Jason.

```elixir
iex> typeid
#Typeid<"user_01hz6wxrw2ecmtwaqhnnpr275f">
iex> Jason.encode(%{id: typeid})
{:ok, "{\"id\":\"user_01hz6wxrw2ecmtwaqhnnpr275f\"}"}
```
