Skip to content

Commit

Permalink
Update docs and doctests
Browse files Browse the repository at this point in the history
  • Loading branch information
ryanwinchester committed Mar 31, 2024
1 parent 2090e09 commit 2247e31
Show file tree
Hide file tree
Showing 4 changed files with 90 additions and 8 deletions.
8 changes: 5 additions & 3 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,9 @@
[![Hex.pm](https://img.shields.io/hexpm/dt/uuid_v7)](https://hex.pm/packages/uuid_v7)
[![Hex.pm](https://img.shields.io/hexpm/l/uuid_v7)](https://github.com/ryanwinchester/uuidv7/blob/main/LICENSE)

UUIDv7 for Elixir and Ecto, using microseconds.
UUIDv7 for Elixir and (optionally) Ecto, using microseconds.

There are other UUID v7 packages, but I wanted the additional clock precision.

Uses the method described in **[Section 6.2](https://www.ietf.org/archive/id/draft-ietf-uuidrev-rfc4122bis-14.html#name-monotonicity-and-counters), Method 3**
from [this IETF Draft](https://www.ietf.org/archive/id/draft-ietf-uuidrev-rfc4122bis-14.html)
Expand All @@ -18,7 +20,7 @@ The package can be installed by adding `uuid_v7` to your list of dependencies in
```elixir
def deps do
[
{:uuid_v7, "~> 0.2.1"}
{:uuid_v7, "~> 0.2.2"}
]
end
```
Expand All @@ -35,7 +37,7 @@ iex> UUIDv7.bingenerate()

## Usage with Ecto

Use this the same way you would use `Ecto.UUID`:
Use this the same way you would use `Ecto.UUID`. For example:

```elixir
defmodule MyApp.Blog.Post do
Expand Down
63 changes: 62 additions & 1 deletion lib/uuidv7.ex
Original file line number Diff line number Diff line change
@@ -1,6 +1,20 @@
defmodule UUIDv7 do
@moduledoc """
UUIDv7 for Elixir (and Ecto).
UUIDv7 for Elixir.
Used for generating version 7 UUIDs using microseconds for increased clock
precision.
Includes `Ecto.Type` implementations.
## Examples
iex> UUIDv7.generate()
"018e90d8-06e8-7f9f-bfd7-6730ba98a51b"
iex> UUIDv7.bingenerate()
<<1, 142, 144, 216, 6, 232, 127, 159, 191, 215, 103, 48, 186, 152, 165, 27>>
"""

@typedoc """
Expand All @@ -15,12 +29,24 @@ defmodule UUIDv7 do

@doc """
Generates a version 7 UUID using microseconds for increased clock precision.
## Example
iex> UUIDv7.generate()
"018e90d8-06e8-7f9f-bfd7-6730ba98a51b"
"""
@spec generate() :: t
def generate, do: bingenerate() |> encode()

@doc """
Generates a version 7 UUID in the binary format.
## Example
iex> UUIDv7.bingenerate()
<<1, 142, 144, 216, 6, 232, 127, 159, 191, 215, 103, 48, 186, 152, 165, 27>>
"""
@spec bingenerate() :: raw
def bingenerate do
Expand All @@ -29,6 +55,17 @@ defmodule UUIDv7 do

@doc """
Generates a version 7 UUID from an existing microsecond timestamp.
## Examples
iex> timestamp = System.system_time(:microsecond)
iex> UUIDv7.from_timestamp(timestamp)
<<1, 142, 144, 216, 6, 232, 127, 159, 191, 215, 103, 48, 186, 152, 165, 27>>
iex> timestamp = DateTime.utc_now()
iex> UUIDv7.from_timestamp(timestamp)
<<1, 142, 144, 216, 6, 232, 127, 159, 191, 215, 103, 48, 186, 152, 165, 27>>
"""
@spec from_timestamp(pos_integer() | DateTime.t()) :: raw()
def from_timestamp(%DateTime{} = datetime) do
Expand All @@ -48,6 +85,15 @@ defmodule UUIDv7 do
<<ms::big-unsigned-48, 7::4, extra_time::big-unsigned-10, rand_a::2, 2::2, rand_b::62>>
end

@doc """
Encode a raw UUID to the string representation.
## Example
iex> UUIDv7.encode(<<1, 142, 144, 216, 6, 232, 127, 159, 191, 215, 103, 48, 186, 152, 165, 27>>)
"018e90d8-06e8-7f9f-bfd7-6730ba98a51b"
"""
@spec encode(raw) :: t
def encode(
<<a1::4, a2::4, a3::4, a4::4, a5::4, a6::4, a7::4, a8::4, b1::4, b2::4, b3::4, b4::4,
Expand Down Expand Up @@ -78,6 +124,15 @@ defmodule UUIDv7 do
defp e(14), do: ?e
defp e(15), do: ?f

@doc """
Decode a string representation of a UUID to the raw binary version.
## Example
iex> UUIDv7.decode("018e90d8-06e8-7f9f-bfd7-6730ba98a51b")
<<1, 142, 144, 216, 6, 232, 127, 159, 191, 215, 103, 48, 186, 152, 165, 27>>
"""
@spec decode(t) :: raw | :error
def decode(
<<a1, a2, a3, a4, a5, a6, a7, a8, ?-, b1, b2, b3, b4, ?-, c1, c2, c3, c4, ?-, d1, d2, d3,
Expand Down Expand Up @@ -154,6 +209,7 @@ defmodule UUIDv7 do
{:ok, "77617265-686f-7573-6520-776f726b6572"}
"""
@doc group: :ecto
@impl Ecto.Type
@spec cast(t | raw | any) :: {:ok, t} | :error
def cast(uuid)
Expand All @@ -177,6 +233,7 @@ defmodule UUIDv7 do
@doc """
Same as `cast/1` but raises `Ecto.CastError` on invalid arguments.
"""
@doc group: :ecto
@spec cast!(t | raw | any) :: t
def cast!(uuid) do
case cast(uuid) do
Expand Down Expand Up @@ -214,6 +271,7 @@ defmodule UUIDv7 do
@doc """
Converts a string representing a UUID into a raw binary.
"""
@doc group: :ecto
@impl Ecto.Type
@spec dump(uuid_string :: t | any) :: {:ok, raw} | :error
def dump(uuid_string)
Expand All @@ -228,6 +286,7 @@ defmodule UUIDv7 do
@doc """
Same as `dump/1` but raises `Ecto.ArgumentError` on invalid arguments.
"""
@doc group: :ecto
@spec dump!(t | any) :: raw
def dump!(uuid) do
with :error <- decode(uuid) do
Expand All @@ -238,6 +297,7 @@ defmodule UUIDv7 do
@doc """
Converts a binary UUID into a string.
"""
@doc group: :ecto
@impl Ecto.Type
@spec load(raw | any) :: {:ok, t} | :error
def load(<<_::128>> = raw_uuid), do: {:ok, encode(raw_uuid)}
Expand All @@ -253,6 +313,7 @@ defmodule UUIDv7 do
@doc """
Same as `load/1` but raises `Ecto.ArgumentError` on invalid arguments.
"""
@doc group: :ecto
@spec load!(raw | any) :: t
def load!(value) do
case load(value) do
Expand Down
25 changes: 22 additions & 3 deletions mix.exs
Original file line number Diff line number Diff line change
@@ -1,19 +1,23 @@
defmodule UUIDv7.MixProject do
use Mix.Project

@version "0.2.2"

@repo_url "https://github.com/ryanwinchester/uuidv7"

def project do
[
app: :uuid_v7,
version: "0.2.1",
version: @version,
elixir: "~> 1.16",
start_permanent: Mix.env() == :prod,
deps: deps(),
description: description(),
package: package(),
source_url: @repo_url,
homepage_url: @repo_url
homepage_url: @repo_url,
name: "UUIDv7",
docs: docs()
]
end

Expand Down Expand Up @@ -44,7 +48,22 @@ defmodule UUIDv7.MixProject do
defp package do
[
licenses: ["MIT"],
links: %{"GitHub" => @repo_url}
links: %{"GitHub" => @repo_url},
maintainers: ["Ryan Winchester"]
]
end

defp docs do
[
main: "UUIDv7",
source_url: @repo_url,
groups_for_docs: [
Types: &(&1[:kind] == :type),
"Ecto.Type Functions": fn fun ->
fun[:group] == :ecto or fun[:name] in [:embed_as, :equal?]
end,
Functions: &(&1[:kind] == :function)
]
]
end
end
2 changes: 1 addition & 1 deletion test/uuidv7_test.exs
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
defmodule UUIDv7Test do
use ExUnit.Case, async: true

doctest UUIDv7
doctest UUIDv7, except: [:moduledoc, generate: 0, bingenerate: 0, from_timestamp: 1]

test "generates uuid string" do
assert <<_::288>> = UUIDv7.generate()
Expand Down

0 comments on commit 2247e31

Please sign in to comment.