- Ruby 82.1%
- JavaScript 17.5%
- Shell 0.4%
| Filename | Latest commit message | Latest commit date |
|---|---|---|
Implements the expanded UEID Specification v1 (full bit layout + encoding + parsing). The spec repo's references in the README were unqualified, and a future reader would reasonably expect ueid-spec to define the whole format, not just the model field algorithm. Spec conformance: - conformance/roundtrip-vectors.json: 8 vectors pinning every field of a UEID (unix_ts_ms, ver, model, count, var, random, hex, dashed, undashed). Mirrors the canonical set in ueid-spec. - scripts/generate-roundtrip-vectors.js: regenerate the file when the bit layout or encoding changes. - scripts/check-conformance.rb: now verifies BOTH the model- hash vectors and the round-trip vectors. - spec/conformance/roundtrip_spec.rb: 7 RSpec cases covering round-trip, layout invariants, fixed-bit validation, dashed/undashed forms. Bug fix from the spec work: - The hardcoded test-vector string used in spec/ueid_spec.rb and spec/ueid/ueid_spec.rb was '019c2c83-8104-83fa-8417-5fb7e28a5464', whose group 3 encoded model=65, count=7 in its bits — not the documented model=63 (String), count=10. Corrected to '019c2c83-8104-83fa-8000-1fb7e28a5464' everywhere. Spec compliance: - UEID::UEID.from_s now rejects strings whose ver field is not 0b1000 or whose var field is not 0b10, per SPECIFICATION.md §2.2 and §2.5. Previous behaviour silently accepted any 32-hex-char string regardless of reserved bits. Throws UEID::Error on mismatch. Version bumped to 0.2.1. |
||
| .github/workflows | ||
| bin | ||
| conformance | ||
| lib | ||
| scripts | ||
| sig | ||
| spec | ||
| .gitignore | ||
| .rspec | ||
| .standard.yml | ||
| CHANGELOG.md | ||
| CODE_OF_CONDUCT.md | ||
| Gemfile | ||
| Gemfile.lock | ||
| LICENSE.txt | ||
| mise.toml | ||
| Rakefile | ||
| README.md | ||
| ueid.gemspec | ||
ueid-ruby
Ruby implementation of Universal Entity IDs (UEIDs) for universal, machine-identifiable record identifiers.
Explanation
UEIDs are designed along the same principle as UXIDs, which are human-friendly identifiers that enable easy identification of an entity's type from its ID. However, UXIDs are optimized for human readability, and are typically stored as strings. In contrast, UEIDs are optimized for machine processing and storage efficiency, making them suitable for use in databases and systems where compactness and speed are critical.
UEIDs are an implementation of the UUID Version
8
standard, combining the timestamp-ordering of UUID version 7, a custom field
identifying the entity type, a sequential component for intra-millisecond
uniqueness, and a random component for global uniqueness. They can be stored
using the native UUID data types of modern databases, such as PostgreSQL's
uuid type, allowing for more efficient storage and indexing compared to
string-based identifiers.
0 1 2 3
0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| unix_ts_ms |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| unix_ts_ms | ver | model | count |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|var| random |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| random |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
Fields
unix_ts_ms (48 bits)
A 48 bit big-endian unsigned integer of the Unix epoch timestamp in milliseconds, according to the Timestamp Considerations of the UUID specification. This is identical to the timestamp field of UUIDv7.
ver (4 bits)
The 4 bit UUIDv8 version as per the Version Field format of the UUID specification.
model (8 bits)
An 8 bit unsigned integer uniquely identifying the entity type or model. The algorithm for computing this field is defined by the UEID Model ID Specification, Version 1. Briefly: the model identifier string is encoded as UTF-8, hashed with FNV-1a-32, then iteratively folded to 8 bits. Test vectors and the canonical reference implementation are in the spec repository.
count (4 bits)
A 4 bit unsigned integer counter that increments with each UEID generated within the same millisecond timestamp and for the same model. This guarantees at least 16 unique UEIDs can be generated per model per millisecond.
var (2 bits)
The 2 bit UUID variant as per the Variant Field format of the UUID specification.
random (62 bits)
The final 62 bit of pseudo-random data to provide uniqueness as per the Unguessability best practices of the UUID specification.
Limitations
- Model identifiers are only unique within a single application or system. Different applications may use the same model identifiers for different entity types.
- The 8 bit
modelfield is a 256-bucket hash. Two different identifiers have a 50% chance of colliding once you register roughly 20 of them (birthday paradox).Registry.collision_policycontrols what happens on collision::error(the default in 0.2.0+; raisesUEID::Errorso conflicts surface at registration time),:warn(logs and overwrites),:overwrite(silent, the historical behaviour). For any non-trivial application, leave the default in place and rename the colliding identifier. - The theoretical maximum is 256 unique entity types per application, but in practice you should expect collisions well before that ceiling.
- UEIDs can guarantee a maximum of 16 unique IDs per model per millisecond. Applications requiring higher throughput may need to implement additional mechanisms to guarantee uniqueness.
- Only 62 bits of randomness are provided, compared to the 74 bits in UUIDv7 and 122 bits in UUIDv4. While this is generally sufficient for most applications, it may not be suitable for scenarios requiring extremely high levels of uniqueness or security.
Usage
This gem provides modules and classes to generate and parse UEIDs in Ruby, using only the Ruby standard library with no external dependencies. It aims to be compatible with Ruby version 3.2 or later, and any Ruby database library that supports UUID, binary, string, or bytea data types, such as ActiveRecord, Sequel, or ROM.
Installation
Add this line to your application's Gemfile:
gem 'ueid'
or install it yourself with:
gem install ueid
# or
bundle add ueid
Examples
require 'ueid'
class MyModel; end
# Generate a UEID for a specific model class...
UEID.generate(MyModel)
# ...or for a specific object
object = MyModel.new()
UEID.generate(object.class)
# Or pass an explicit model id when class.name is unstable:
UEID.generate(MyModel, "my_model")
Model ID Specification
The 8-bit model field is computed from a string identifier using the
algorithm defined by the UEID Specification, Version
1. Conformance is
verified against conformance/vectors.json (model-hash) and
conformance/roundtrip-vectors.json (full bit layout) in this
repository, both mirroring the canonical test-vector sets in the spec repo.
Override Registry.model_id_for(klass) to use a custom string instead of
klass.name. Pass an explicit id to UEID.generate(klass, "my_id") or
Registry.hash_for_class(klass, "my_id") to override per call.
The default collision policy in 0.2.0+ is :error: a registration that
would overwrite a different class's binding raises UEID::Error. To take
the historical silent-overwrite behaviour, set
Registry.collision_policy = :overwrite early in your boot sequence.
ActiveRecord Example
After configuring your application to use UUIDs as primary
keys,
you can configure your base ApplicationRecord class to assign UEID primary
keys to new records:
class ApplicationRecord < ActiveRecord::Base
# ...
before_create :assign_ueid
# ...
private
def assign_ueid
self.id ||= UEID.generate(self.class)
end
end
Development
Requirements
- Ruby 3.2 or later
- (optional) mise
Setup
git clone https://tangled.org/did:plc:hfjjkmleodmclbfae27m3ngt/ueid-ruby.git
cd ueid-ruby
# If you use mise and don't have ruby installed system-wide:
mise trust
mise install
bin/setup
Testing
bundle exec rake test
The conformance suite (spec/conformance/model_id_spec.rb) verifies every
test vector in conformance/vectors.json. Run it in CI on every push to
catch drift from the spec.
UEID Specification
This gem implements the UEID Specification, Version
1. The full algorithm
contract — bit layout, encoding, parsing rules, the FNV-1a-32 + iterative
xor-shift fold that produces the model field, the conformance checklist,
and the round-trip vectors that pin every field of a UEID — is in
SPECIFICATION.md
in the spec repository. Test vectors live at
conformance/vectors.json
(model-hash) and
conformance/roundtrip-vectors.json
(full-bit-layout), both mirrored in this repository at
conformance/vectors.json and conformance/roundtrip-vectors.json.
License
The gem is available as open source under the terms of the MIT License.
Code of Conduct
Everyone interacting with the UEID project through code contributions and all communication channels must abide by the code of conduct. Violations of the code of conduct may result in banishment from the project at the discretion of the project maintainers.