Skip to content

Commit

Permalink
Add uuid_v7 support
Browse files Browse the repository at this point in the history
UUIDv7, currently RFC is a new version that allows for time
ordering thanks to a unix timestamp component.

@see https://datatracker.ietf.org/doc/draft-peabody-dispatch-new-uuid-format/04/
  • Loading branch information
khasinski committed Nov 3, 2022
1 parent fbce06e commit 84fa9eb
Show file tree
Hide file tree
Showing 3 changed files with 41 additions and 1 deletion.
9 changes: 8 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -53,13 +53,20 @@ SecureRandom.alphanumeric(10) #=> "S8baxMJnPl"
SecureRandom.alphanumeric(10) #=> "aOxAg8BAJe"
```

Generate UUIDs:
Generate UUIDs v4 (random):

```ruby
SecureRandom.uuid #=> "2d931510-d99f-494a-8c67-87feb05e1594"
SecureRandom.uuid #=> "bad85eb9-0713-4da7-8d36-07a8e4b00eab"
```

Generate UUIDs v7 (unix timestamp + random):

```ruby
SecureRandom.uuid_v7 #=> "01843a55-736e-785c-9f2e-0f74f11d6145"
SecureRandom.uuid_v7 #=> "01843a55-7370-799e-8498-669a5b1fbc19"
```

## Development

After checking out the repo, run `bin/setup` to install dependencies. Then, run `rake test` to run the tests. You can also run `bin/console` for an interactive prompt that will allow you to experiment.
Expand Down
22 changes: 22 additions & 0 deletions lib/random/formatter.rb
Original file line number Diff line number Diff line change
Expand Up @@ -148,6 +148,28 @@ def uuid
"%08x-%04x-%04x-%04x-%04x%08x" % ary
end

# Random::Formatter#uuid generates a random v7 UUID (Universally Unique IDentifier).
#
# require 'random/formatter'
#
# prng.uuid_v7 #=> "01843a54-f268-7f51-934c-216e9ca4fe05"
# prng.uuid_v7 #=> "01843a54-f26b-7edf-862b-d986fb0f421b"
# prng.uuid_v7 #=> "01843a54-f26f-7664-b455-85fa8a5e6a4d"
#
# The version 7 UUID is random, but contains a time-based component for ordering.
#
# The result contains 74 random bits (9 random bytes).
#
# See RFC 4122 for details of UUID.
#
def uuid_v7
ts = [Process.clock_gettime(Process::CLOCK_REALTIME, :millisecond)].pack('Q>').unpack('nNn').drop(1)
ary = random_bytes(10).unpack("nnnN")
ary[0] = (ary[0] & 0x0fff) | 0x7000
ary[1] = (ary[1] & 0x3fff) | 0x8000
"%08x-%04x-%04x-%04x-%04x%08x" % (ts + ary)
end

private def gen_random(n)
self.bytes(n)
end
Expand Down
11 changes: 11 additions & 0 deletions test/ruby/test_random_formatter.rb
Original file line number Diff line number Diff line change
Expand Up @@ -75,6 +75,17 @@ def test_uuid
assert_match(/\A\h{8}-\h{4}-\h{4}-\h{4}-\h{12}\z/, uuid)
end

def test_uuid_v7
uuid = @it.uuid_v7
assert_equal(36, uuid.size)

# Check time_hi_and_version and clock_seq_hi_res bits (RFC 4122 4.4)
assert_equal('7', uuid[14])
assert_include(%w'8 9 a b', uuid[19])

assert_match(/\A\h{8}-\h{4}-\h{4}-\h{4}-\h{12}\z/, uuid)
end

def test_alphanumeric
65.times do |n|
an = @it.alphanumeric(n)
Expand Down

0 comments on commit 84fa9eb

Please sign in to comment.