Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add Firebase base64 variant #13

Open
wants to merge 4 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
26 changes: 20 additions & 6 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
# Ecto.ULID

An `Ecto.Type` implementation of [ULID](https://github.com/ulid/spec).
An `Ecto.ParameterizedType` implementation of [ULID](https://github.com/ulid/spec).

`Ecto.ULID` should be compatible anywhere that `Ecto.UUID` is supported. It has been confirmed to
work with PostgreSQL and MySQL on Ecto 2.x and 3.x. Ecto 1.x is *not* supported.
Expand Down Expand Up @@ -33,11 +33,11 @@ The following are results from running the benchmark on an AMD Ryzen Threadrippe

```
benchmark name iterations average time
cast/1 10000000 0.25 µs/op
cast/2 10000000 0.25 µs/op
dump/1 10000000 0.50 µs/op
load/1 10000000 0.55 µs/op
bingenerate/0 10000000 0.93 µs/op
generate/0 1000000 1.55 µs/op
load/2 10000000 0.55 µs/op
bingenerate/1 10000000 0.93 µs/op
generate/2 1000000 1.55 µs/op
```

## Usage
Expand Down Expand Up @@ -106,9 +106,23 @@ end
`Ecto.ULID` supports `autogenerate: true` as well as `autogenerate: false` when used as the primary
key.

`Ecto.ULID` also supports `variant: :b64` as well as `variant: :push` that follows the compact 20-char string encoding standard defined in [Firebase Push Key](https://firebase.googleblog.com/2015/02/the-2120-ways-to-ensure-unique_68.html). Just like the default Crockford base32 encoding, both variants use a modified base64 alphabet to ensure the IDs will still sort correctly when ordered lexicographically. Do note that the `:push` variant encodes only 120-bits, but is otherwise interoperable with the standard 128-bit binary ULID (by having the 1st-byte of the random component set to 0, we achieve a more efficient base64 encoding that saves 2 characters).

```elixir
defmodule MyApp.Event do
use Ecto.Schema

@primary_key {:id, Ecto.ULID, autogenerate: false, variant: :b64}
@foreign_key_type Ecto.ULID
schema "events" do
# more columns ...
end
end
```

### Application Usage

A ULID can be generated in string or binary format by calling `generate/0` or `bingenerate/0`. This
A ULID can be generated in string or binary format by calling `generate/2` or `bingenerate/1`. This
can be useful when generating ULIDs to send to external systems:

```elixir
Expand Down
42 changes: 38 additions & 4 deletions bench/ulid_bench.exs
Original file line number Diff line number Diff line change
@@ -1,25 +1,59 @@
defmodule ULIDBench do
use Benchfella

bench "generate/0" do
bench "generate/2" do
Ecto.ULID.generate()
nil
end

bench "bingenerate/0" do
bench "generate/2 (:b64)" do
Ecto.ULID.generate(:b64)
nil
end

bench "generate/2 (:push)" do
Ecto.ULID.generate(:push)
nil
end

bench "bingenerate/1" do
Ecto.ULID.bingenerate()
nil
end

bench "cast/1" do
bench "cast/2" do
Ecto.ULID.cast("01C0M0Y7BG2NMB15VVVJH807F3")
end

bench "cast/2 (:b64)" do
Ecto.ULID.cast("-0N1VE6M-KPA1MTxmXV0rY")
end

bench "cast/2 (:push)" do
Ecto.ULID.cast("-L-c2lpkPA1MTxmXV0rY")
end

bench "dump/1" do
Ecto.ULID.dump("01C0M0Y7BG2NMB15VVVJH807F3")
end

bench "load/1" do
bench "dump/1 (:b64)" do
Ecto.ULID.dump("-0N1VE6M-KPA1MTxmXV0rY")
end

bench "dump/1 (:push)" do
Ecto.ULID.dump("-L-c2lpkPA1MTxmXV0rY")
end

bench "load/2" do
Ecto.ULID.load(<<1, 96, 40, 15, 29, 112, 21, 104, 176, 151, 123, 220, 162, 128, 29, 227>>)
end

bench "load/2 (:b64)" do
Ecto.ULID.load(<<1, 96, 40, 15, 29, 112, 21, 104, 176, 151, 123, 220, 162, 128, 29, 227>>, :b64)
end

bench "load/2 (:push)" do
Ecto.ULID.load(<<1, 96, 40, 15, 29, 112, 21, 104, 176, 151, 123, 220, 162, 128, 29, 227>>, :push)
end
end
Loading