README.md

# TUID
## Tagged Unique IDs


Developer Friendly:

- K-sortable
- Collision-free, coordination-free, dependency-free
- Just strings on the outside
- Tagged with underscore prefix to help with validation and act as a psuedo-type
- UUIDv7 encodes creation date

User Friendly:

- Base58 encoded
    - Shorten string representation in URLs and other places
    - Prevent confusing letters like lowercase L or Oh/zero
- Tagged with underscore prefix to reduce confusion
- Copy/paste friendly, double-click selectable


## Installation

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

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

Add the following code to a single schema module to use TUID columns like so:

```elixir

  @primary_key {:id, TUID, prefix: unquote(prefix), autogenerate: true}
  @foreign_key_type TUID
  schema "books" do
    field :title, :string
    field :author, :string
  end
```

Migrations should look like the following:

```elixir

  create table(:books, primary_key: false) do
    add :id, :uuid, primary_key: true
    add :title, :string
    add :author, :string
  end
```

You may also create `MyApp.Schema` module and use that in place of `Ecto.Schema` in your schema modules.
Typically, the `MyApp.Schema` is saved to `lib/my_app/schema.ex`

```elixir
defmodule MyApp.Schema do
  @moduledoc """
  This module defines the default schema settings for schema modules
  in MyApp.

  Primary and foreign keys use TUIDs.

  ## Usage

      defmodule MyApp.Accounts.Account do
        use MyApp.Schema, prefix: "acct"

        # ...
      end
  """

  defmacro __using__(opts \\ []) do
    prefix = Keyword.fetch!(opts, :prefix)

    quote do
      use Ecto.Schema

      @primary_key {:id, TUID.ParameterizedType, prefix: unquote(prefix), autogenerate: true}
      @foreign_key_type TUID.ParameterizedType

      @type t :: %__MODULE__{}
    end
  end
end
```

Schema modules then should look like:

```elixir

defmodule MyApp.Library.Book do
  use MyApp.Schema, prefix: "book"

  import Ecto.Changeset

  schema "books" do
    field :title, :string
    field :author, :string
  end

  ...
     
end
```

## Credit and inspiration

This project is based on the code and blog post from Dan Shultzer's base 62 implementation. 

https://danschultzer.com/posts/prefixed-base62-uuidv7-object-ids-with-ecto


## Other projects of similar nature


- ksuid
    - https://github.com/segmentio/ksuid
- TypeID
    - https://github.com/jetpack-io/typeid