typeid
This library implements a type-safe, K-sortable, globally unique identifier (TypeID) generator, as specified at:
https://github.com/jetify-com/typeid/tree/main/spec
A TypeID is the concatenation of a type prefix and a version 7 UUID
suffix, separated by an underscore, e.g.
user_01h2xcejqtf2nbrexx3vqjhp41. The type prefix is a, possibly
empty, lowercase string that, together with a leading “_” separator
when non-empty, identifies the “type” of the entity that the identifier
refers to. The UUID suffix is always a fixed 26 character string that
encodes the 128 bits of a UUID using a strict, lowercase variant of
Crockford base32 (the alphabet used is
0123456789abcdefghjkmnpqrstvwxyz, i.e. the letters “i”, “l”, “o”,
and “u” are not used, avoiding ambiguity with “1”, “1”, “0”, and
“v”/”y”). This base32 variant is unrelated to the RFC 4648 base32
encoding implemented by the base32 library: the suffix always
encodes exactly 128 bits (the two zero bits conceptually prepended to a
UUID plus its 128 bits are split into 26 groups of 5 bits, most
significant group first) using no padding, whereas RFC 4648 base32
encodes byte streams of any length in 40-bit (5-byte) chunks, using “=”
padding for partial chunks.
Generation always uses a version 7 UUID, which is time-ordered using a
Unix Epoch timestamp in milliseconds, as specified in RFC 9562, making
the generated TypeIDs K-sortable. Decoding a TypeID from an user
provided UUID (using the from_uuid/3 predicate) accepts any UUID
version, however, as implementations are expected to allow encoding of
other UUID versions at the user discretion.
TypeIDs can be generated as atoms, lists of characters, or lists of character codes.
See also the cuid2, ksuid, ids, nanoid, snowflakeid,
ulid, and uuid libraries.
API documentation
Open the ../../apis/library_index.html#typeid link in a web browser.
Loading
To load all entities in this library, load the loader.lgt file:
| ?- logtalk_load(typeid(loader)).
Testing
To test this library predicates, load the tester.lgt file:
| ?- logtalk_load(typeid(tester)).
Generating TypeIDs
By default, TypeIDs are generated as atoms. To generate a TypeID with an empty type prefix:
| ?- typeid::generate(TypeID).
TypeID = '01kyaqvrf2f13t3fe2b16329jj'
yes
To generate a TypeID with a given type prefix:
| ?- typeid::generate(user, TypeID).
TypeID = 'user_01kyaqvrf2e2mry9en73p93dkp'
yes
To generate a TypeID using a list of characters representation, use
instead the typeid/1 parametric object:
| ?- typeid(chars)::generate(user, TypeID).
TypeID = [u,s,e,r,'_','0','1',k,y,a,q,v,r,f,'2',e,z,g,'8',z,'7','4',r,r,z,d,'6',g,'8',p,j]
yes
Similarly, to get a TypeID using a list of character codes representation:
| ?- typeid(codes)::generate(user, TypeID).
TypeID = [117,115,101,114,95,48,49,107,121,97,113,118,114,102,50,101,51,107,114,55,109,107,51,118,122,120,106,122,116,114,120]
yes
When the backend only provides access to local time, use generate/3
with the current local UTC offset to compute the UUID timestamp using
UTC:
| ?- typeid::generate(user, '+01:00', TypeID).
TypeID = 'user_01kyaqvrf2f72a4eksrcy9vnwe'
yes
Generation fails if the given type prefix is not valid per the TypeID specification (see below).
Converting to and from UUIDs
To construct a TypeID from an existing UUID (which does not need to be a version 7 UUID):
| ?- typeid::from_uuid(prefix, '0188bac7-4afa-78aa-bc3b-bd1eef28d881', TypeID).
TypeID = 'prefix_01h2xcejqtf2nbrexx3vqjhp41'
yes
To recover the UUID encoded in the suffix of a TypeID:
| ?- typeid::to_uuid('prefix_01h2xcejqtf2nbrexx3vqjhp41', UUID).
UUID = '0188bac7-4afa-78aa-bc3b-bd1eef28d881'
yes
Decomposing and composing TypeIDs
To split a TypeID into its type prefix and its base32 encoded UUID suffix:
| ?- typeid::decompose('prefix_01h2xcejqtf2nbrexx3vqjhp41', Prefix, Suffix).
Prefix = prefix, Suffix = '01h2xcejqtf2nbrexx3vqjhp41'
yes
To perform the reverse operation:
| ?- typeid::compose(prefix, '01h2xcejqtf2nbrexx3vqjhp41', TypeID).
TypeID = 'prefix_01h2xcejqtf2nbrexx3vqjhp41'
yes
The prefix/2 and suffix/2 predicates can also be used to access
just the type prefix or just the UUID suffix of a TypeID.
Validating TypeIDs
To check that a TypeID, a type prefix, or a base32 encoded UUID suffix, is valid per the TypeID specification:
| ?- typeid::valid('prefix_01h2xcejqtf2nbrexx3vqjhp41').
yes
| ?- typeid::valid_prefix(prefix).
yes
| ?- typeid::valid_suffix('01h2xcejqtf2nbrexx3vqjhp41').
yes
A type prefix must be empty or match the regular expression
^[a-z]([a-z_]{0,61}[a-z])?$ (i.e. at most 63 lowercase ASCII
letters, optionally including underscores, but never starting or ending
with an underscore). A base32 encoded UUID suffix must be exactly 26
characters long, using only the strict, lowercase Crockford base32
alphabet described above, with its first character decoding to a value
no greater than 7 (as required for the suffix to represent no more than
the 128 bits of a UUID).