README.md

# Once

Once is an Ecto type for locally unique (unique within your domain or application) 64-bit IDs generated by multiple Elixir nodes. Locally unique IDs make it easier to keep things separated, simplify caching and simplify inserting related things (because you don't have to wait for the database to return the ID).

Because a Once fits into an SQL bigint, they use little space and keep indexes small and fast. Because of their [structure](https://hexdocs.pm/no_noncense/NoNoncense.html#module-nonce-types) they have counter-like data locality, which helps your indexes perform well, [unlike UUIDv4s](https://www.cybertec-postgresql.com/en/unexpected-downsides-of-uuid-keys-in-postgresql/).

Once IDs are base on counter, time-sortable or encrypted nonces. These underlying values can then be encoded in several formats, can be prefixed and can be masked. And you can combine all of these options, providing great flexibility.

The library has only `Ecto` and its sibling `NoNoncense` as dependencies. NoNoncense generates the actual values and performs incredibly well, hitting rates of tens of millions of nonces per second, and it also helps you to safeguard the uniqueness guarantees.

> #### Read the migration guide {: .warning}
>
> If you're upgrading from v0.x.x and you use encrypted IDs, please read the [Migration Guide](MIGRATION.md) carefully - there are breaking changes that require attention to preserve uniqueness guarantees.

## Features

### ID Generation Types

Once supports three types of ID generation:

- **Counter** (default): Really fast to generate, predictable, works well with b-tree indexes
- **Sortable**: Time-sortable like a [Snowflake ID](https://en.wikipedia.org/wiki/Snowflake_ID)
- **Encrypted**: Unique and unpredictable, like a UUIDv4 but shorter

### Flexible Formats

IDs can be represented in multiple formats, both in your Elixir application (`:ex_format`) and in your database (`:db_format`). By default, IDs are url64-encoded 11-character strings in Elixir and signed bigints in the database. You can choose from `:url64`, `:hex`, `:hex32`, `:raw`, `:signed`, or `:unsigned` formats and use `to_format/3` to transform between them.

### Prefixed IDs

Add Stripe-style prefixes to IDs (e.g., `"usr_AV7m9gAAAAU"`) for better debugging, API clarity and type safety. Prefixes can exist only in Elixir or be persisted to the database.

### Masked IDs

Masked IDs provide a middle ground between plaintext and encrypted IDs. They're stored as plaintext in the database (preserving performance) but encrypted when retrieved by the Ecto type, so your application only sees encrypted values.

## Installation

The package is hosted on [hex.pm](https://hex.pm/packages/once) and can be installed by adding `:once` to your list of dependencies in `mix.exs`:

```elixir
def deps do
  [
    {:once, "~> 1.2.1"}
  ]
end
```

## Docs

Documentation can be found on [hexdocs.pm](https://hexdocs.pm/once/).

## Usage

To get going, you need to set up a `NoNoncense` instance to generate the base unique values. Follow [its documentation](https://hexdocs.pm/no_noncense) to do so. `Once` expects an instance with its own module name by default, like so:

```elixir
# application.ex (read the NoNoncense docs!)
machine_id = NoNoncense.MachineId.id!(opts)
NoNoncense.init(name: Once, machine_id: machine_id)

# if you want to use encrypted/masked IDs, also pass a 256-bits key
NoNoncense.init(name: Once, machine_id: machine_id, base_key: System.get_env("ONCE_SECRET_KEY"))
```

In your `Ecto` schemas, you can then use the type:

```elixir
schema "things" do
  field :id, Once, autogenerate: true
end
```

And that's it! Be sure to look at [hexdocs.pm](https://hexdocs.pm/once/) for options and additional info.