README.md

# PrefixedID

This package provides an Ecto type for human readable IDs, like `user_2x2QlH09G3tPrptOPzhr5`, consisting of a string prefix plus a Base62-encoded UUIDv7.

Having different prefixes for each "ID type" makes them more readable, prevents human error, and enables features such as polymorphic lookup.

UUIDv7 generation and Base62 encode/decode are implemented in Rust using a NIF.

Inspiration for this package is taken from:

- <https://danschultzer.com/posts/prefixed-base62-uuidv7-object-ids-with-ecto>
- <https://dev.to/stripe/designing-apis-for-humans-object-ids-3o5a>

## Installation

The package can be installed by adding `prefixed_id` to your list of dependencies in `mix.exs`:

```elixir
def deps do
  [
    {:prefixed_id, "~> 0.1.0"}
  ]
end
```

## Usage

Use `PrefixedID` as the `@primary_key` type in your schema, providing a `prefix`:

```elixir
defmodule MyApp.User do
  use Ecto.Schema
  @primary_key {:id, PrefixedID, prefix: "user", autogenerate: true}
  ...
end
```

If referencing a table with a `PrefixedID` primary key, specify `@foreign_key_type`:

```elixir
defmodule MyApp.UserToken do
  use Ecto.Schema
  @foreign_key_type PrefixedID
  ...
end
```

To use `PrefixedID` for all keys, you can define your own `Schema` module:

```elixir
defmodule MyApp.Schema do
  defmacro __using__(opts) do
    id_prefix = Keyword.fetch!(opts, :id_prefix)

    quote do
      use Ecto.Schema
      @primary_key {:id, PrefixedID, prefix: unquote(id_prefix), autogenerate: true}
      @foreign_key_type PrefixedID
      @timestamps_opts [type: :utc_datetime_usec]
    end
  end
end

defmodule MyApp.User do
  use MyApp.Schema, id_prefix: "user"
  ...
end
```