uuid - UUID Module based on RFC 4122 #
The std/uuid module provides support for Universally Unique Identifiers (UUIDs), implementing RFC 4122 standard UUIDs.
Overview #
UUIDs are 128-bit identifiers that are guaranteed to be unique across space and time. They're commonly used as primary keys in databases, distributed systems identifiers, and anywhere you need globally unique IDs.
Module Import #
use "std/uuid" as uuid
Functions #
uuid.v1(node_id?) #
Generate a UUID version 1 (timestamp and node ID based). Includes timestamp and optionally a node identifier (like MAC address).
Parameters:
node_id(Bytes, optional) - 6-byte node identifier. If omitted, generates random node ID.
Returns: Uuid
Example:
# With random node ID
let id = uuid.v1()
# With specific node ID (e.g., MAC address)
let node = b"\x01\x02\x03\x04\x05\x06"
let id_with_node = uuid.v1(node)
Note: Consider using v6 instead, which has the same features but better ordering properties.
uuid.v3(namespace, name) #
Generate a UUID version 3 (MD5 namespace-based). Creates deterministic UUIDs based on a namespace and name.
Parameters:
namespace(Uuid) - Namespace UUID (useNAMESPACE_DNS,NAMESPACE_URL, etc.)name(Str or Bytes) - Name to hash
Returns: Uuid
Example:
# Generate UUID for a domain name
let id = uuid.v3(uuid.NAMESPACE_DNS, "example.com")
# Same inputs always produce same UUID
let id2 = uuid.v3(uuid.NAMESPACE_DNS, "example.com")
puts(id.eq(id2)) # true
Note: Consider using v5 instead, which uses SHA-1 instead of MD5.
uuid.v4() #
Generate a UUID version 4 (random). Uses random numbers for uniqueness. Best for general-purpose unique identifiers.
Returns: Uuid
Example:
let id = uuid.v4()
puts(id.to_string()) # e.g., "550e8400-e29b-41d4-a716-446655440000"
uuid.v5(namespace, name) #
Generate a UUID version 5 (SHA-1 namespace-based). Creates deterministic UUIDs based on a namespace and name. Preferred over v3.
Parameters:
namespace(Uuid) - Namespace UUID (useNAMESPACE_DNS,NAMESPACE_URL, etc.)name(Str or Bytes) - Name to hash
Returns: Uuid
Example:
# Generate UUID for a URL
let id = uuid.v5(uuid.NAMESPACE_URL, "https://example.com")
# Same inputs always produce same UUID
let id2 = uuid.v5(uuid.NAMESPACE_URL, "https://example.com")
puts(id.eq(id2)) # true
uuid.v6(node_id?) #
Generate a UUID version 6 (improved timestamp-based). Like v1 but with better ordering properties. Preferred over v1.
Parameters:
node_id(Bytes, optional) - 6-byte node identifier. If omitted, generates random node ID.
Returns: Uuid
Example:
let id = uuid.v6()
# With specific node ID
let node = b"\xAA\xBB\xCC\xDD\xEE\xFF"
let id_with_node = uuid.v6(node)
uuid.v7() #
Generate a UUID version 7 (time-ordered). Includes Unix timestamp, making it sortable and optimal for database indexes.
Returns: Uuid
Example:
let id1 = uuid.v7()
let id2 = uuid.v7()
# v7 UUIDs are lexicographically sortable
puts(id1.to_string() < id2.to_string()) # true (usually)
Benefits of v7:
- Sortable: Can be used as sortable primary keys
- Index-friendly: Best database index performance
- Time-ordered: Contains creation timestamp
- Sequential: Reduces index fragmentation
uuid.v8(data) #
Generate a UUID version 8 (custom). Allows creating UUIDs from custom 16-byte data.
Parameters:
data(Bytes) - Exactly 16 bytes of custom data
Returns: Uuid
Example:
let custom_data = b"\x01\x02\x03\x04\x05\x06\x07\x08\x09\x0A\x0B\x0C\x0D\x0E\x0F\x10"
let id = uuid.v8(custom_data)
uuid.nil_uuid() #
Create a nil UUID (all zeros).
Returns: Uuid
Example:
let nil_id = uuid.nil_uuid()
puts(nil_id.to_string()) # "00000000-0000-0000-0000-000000000000"
puts(nil_id.is_nil()) # true
uuid.parse(string) #
Parse a UUID from a string. Accepts both hyphenated and non-hyphenated formats.
Parameters:
string(Str) - UUID string to parse
Returns: Uuid
Raises: Error if the string is not a valid UUID
Example:
# With hyphens
let id1 = uuid.parse("550e8400-e29b-41d4-a716-446655440000")
# Without hyphens
let id2 = uuid.parse("550e8400e29b41d4a716446655440000")
# Both produce the same UUID
puts(id1.to_string()) # "550e8400-e29b-41d4-a716-446655440000"
puts(id2.to_string()) # "550e8400-e29b-41d4-a716-446655440000"
uuid.from_bytes(bytes) #
Create a UUID from exactly 16 bytes.
Parameters:
bytes(Bytes) - 16-byte sequence
Returns: Uuid
Raises: Error if bytes length is not exactly 16
Example:
let id = uuid.v4()
let bytes = id.to_bytes()
let reconstructed = uuid.from_bytes(bytes)
puts(id.to_string() == reconstructed.to_string()) # true
Namespace Constants #
The UUID module provides standard namespace UUIDs for use with v3 and v5:
uuid.NAMESPACE_DNS #
Namespace for domain names (DNS).
Example:
let id = uuid.v5(uuid.NAMESPACE_DNS, "example.com")
uuid.NAMESPACE_URL #
Namespace for URLs.
Example:
let id = uuid.v5(uuid.NAMESPACE_URL, "https://example.com")
uuid.NAMESPACE_OID #
Namespace for ISO Object Identifiers (OID).
Example:
let id = uuid.v5(uuid.NAMESPACE_OID, "1.3.6.1.4.1")
uuid.NAMESPACE_X500 #
Namespace for X.500 Distinguished Names.
Example:
let id = uuid.v5(uuid.NAMESPACE_X500, "CN=example,DC=com")
UUID Methods #
id.to_string() / id.str() #
Convert UUID to its standard hyphenated lowercase string representation.
Returns: Str
Example:
let id = uuid.v4()
puts(id.to_string()) # "550e8400-e29b-41d4-a716-446655440000"
id.to_hyphenated() #
Convert UUID to hyphenated format (same as to_string()).
Returns: Str
Example:
let id = uuid.v4()
puts(id.to_hyphenated()) # "550e8400-e29b-41d4-a716-446655440000"
id.to_simple() #
Convert UUID to simple format without hyphens.
Returns: Str
Example:
let id = uuid.parse("550e8400-e29b-41d4-a716-446655440000")
puts(id.to_simple()) # "550e8400e29b41d4a716446655440000"
id.to_urn() #
Convert UUID to URN format.
Returns: Str
Example:
let id = uuid.v4()
puts(id.to_urn()) # "urn:uuid:550e8400-e29b-41d4-a716-446655440000"
id.to_bytes() #
Convert UUID to its 16-byte representation.
Returns: Bytes
Example:
let id = uuid.v4()
let bytes = id.to_bytes()
puts(bytes.len()) # 16
id.version() #
Get the UUID version number.
Returns: Num - Version number (e.g., 4 for UUIDv4)
Example:
let id = uuid.v4()
puts(id.version()) # 4
id.variant() #
Get the UUID variant as a string.
Returns: Str - Variant name (e.g., "RFC4122")
Example:
let id = uuid.v4()
puts(id.variant()) # "RFC4122"
id.is_nil() #
Check if the UUID is the nil UUID (all zeros).
Returns: Bool
Example:
let nil_id = uuid.nil_uuid()
let normal_id = uuid.v4()
puts(nil_id.is_nil()) # true
puts(normal_id.is_nil()) # false
id.eq(other) #
Check if two UUIDs are equal.
Parameters:
other(Uuid) - UUID to compare with
Returns: Bool
Example:
let id1 = uuid.parse("550e8400-e29b-41d4-a716-446655440000")
let id2 = uuid.parse("550e8400-e29b-41d4-a716-446655440000")
let id3 = uuid.v4()
puts(id1.eq(id2)) # true
puts(id1.eq(id3)) # false
id.neq(other) #
Check if two UUIDs are not equal.
Parameters:
other(Uuid) - UUID to compare with
Returns: Bool
Example:
let id1 = uuid.v4()
let id2 = uuid.v4()
puts(id1.neq(id2)) # true (v4 UUIDs are random)
Database Integration #
UUIDs work seamlessly with PostgreSQL's native UUID type:
use "std/db/postgres" as db
use "std/uuid" as uuid
let conn = db.connect("host=localhost user=myuser dbname=mydb")
let cursor = conn.cursor()
# Create table with UUID primary key
cursor.execute("CREATE TABLE users (id UUID PRIMARY KEY, name TEXT)")
# Insert with UUID (v7 recommended for better index performance)
let user_id = uuid.v7()
cursor.execute("INSERT INTO users (id, name) VALUES ($1, $2)", [user_id, "Alice"])
# Query by UUID
cursor.execute("SELECT * FROM users WHERE id = $1", [user_id])
let rows = cursor.fetch_all()
puts(rows[0].get("name")) # "Alice"
# Retrieved UUID is a Uuid type
let retrieved_id = rows[0].get("id")
puts(retrieved_id.cls()) # "Uuid"
puts(retrieved_id.to_string()) # Same as user_id
Common Patterns #
Using UUIDs as Primary Keys #
With v7 (recommended for databases):
use "std/db/postgres" as db
use "std/uuid" as uuid
fun create_user(conn, name, email)
let cursor = conn.cursor()
# v7 UUIDs are sortable and index-friendly
let user_id = uuid.v7()
cursor.execute(
"INSERT INTO users (id, name, email) VALUES ($1, $2, $3)",
[user_id, name, email]
)
user_id
end
# Usage
let conn = db.connect("...")
let new_user_id = create_user(conn, "Alice", "alice@example.com")
puts("Created user: " .. new_user_id.to_string())
With v4 (when unpredictability is important):
# Use v4 when you need random, unpredictable IDs
let api_key_id = uuid.v4()
UUID Validation #
use "std/uuid" as uuid
fun is_valid_uuid(str)
try
uuid.parse(str)
true
catch e
false
end
end
puts(is_valid_uuid("550e8400-e29b-41d4-a716-446655440000")) # true
puts(is_valid_uuid("not-a-uuid")) # false
Storing UUIDs as Strings #
If your database doesn't support UUID types, you can convert to strings:
use "std/db/sqlite" as db
use "std/uuid" as uuid
let conn = db.connect(":memory:")
let cursor = conn.cursor()
cursor.execute("CREATE TABLE items (id TEXT PRIMARY KEY, name TEXT)")
let item_id = uuid.v4()
cursor.execute("INSERT INTO items VALUES (?, ?)", [item_id.to_string(), "Item 1"])
cursor.execute("SELECT id FROM items")
let rows = cursor.fetch_all()
let retrieved_id = uuid.parse(rows[0].get("id")) # Convert back to UUID
Comparing UUIDs #
use "std/uuid" as uuid
let id1 = uuid.v4()
let id2 = uuid.v4()
let id3 = uuid.parse(id1.to_string())
# Direct comparison using methods
puts(id1.eq(id2)) # false (different UUIDs)
puts(id1.eq(id3)) # true (same UUID)
# String comparison
puts(id1.to_string() == id2.to_string()) # false
puts(id1.to_string() == id3.to_string()) # true
Deterministic UUIDs for Idempotency #
Use v5 (or v3) to create deterministic UUIDs from known data:
use "std/uuid" as uuid
fun get_user_uuid(email)
# Always returns same UUID for same email
uuid.v5(uuid.NAMESPACE_DNS, email)
end
let alice_id = get_user_uuid("alice@example.com")
let also_alice = get_user_uuid("alice@example.com")
puts(alice_id.eq(also_alice)) # true - same UUID
# Useful for:
# - Idempotent operations
# - Content-addressable storage
# - Deduplication
# - Consistent IDs across systems
Custom UUID Data (v8) #
Create UUIDs with custom embedded data:
use "std/uuid" as uuid
# Embed custom application data in UUID
fun create_sharded_id(shard_num, seq_num)
let data = b"\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00"
# Customize the data bytes as needed
uuid.v8(data)
end
Type Information #
UUIDs are first-class Quest objects:
use "std/uuid" as uuid
let id = uuid.v4()
puts(id.cls()) # "Uuid"
puts(id._doc()) # "UUID (Universally Unique Identifier) value"
puts(id._id()) # Unique object ID (number)
Format Details #
Hyphenated Format (Standard) #
550e8400-e29b-41d4-a716-446655440000
- 8-4-4-4-12 hexadecimal digits
- Lowercase
- Standard representation
Simple Format #
550e8400e29b41d4a716446655440000
- 32 hexadecimal digits
- No hyphens
- Useful for compact storage
URN Format #
urn:uuid:550e8400-e29b-41d4-a716-446655440000
- RFC 4122 URN format
- Prefixed with
urn:uuid:
UUID Versions #
Quest supports generating all standard UUID versions:
Time-based UUIDs #
- UUIDv1 (
uuid.v1()) - Timestamp + node ID. Contains timestamp and node identifier (like MAC address). - UUIDv6 (
uuid.v6()) - Improved v1. Same as v1 but with better ordering properties. Preferred over v1. - UUIDv7 (
uuid.v7()) - Unix timestamp-based. Best for database primary keys due to excellent ordering. Recommended for most time-based use cases.
Name-based UUIDs (Deterministic) #
- UUIDv3 (
uuid.v3(namespace, name)) - MD5 namespace-based. Generates same UUID for same namespace+name. - UUIDv5 (
uuid.v5(namespace, name)) - SHA-1 namespace-based. Same as v3 but uses SHA-1. Preferred over v3.
Other UUIDs #
- UUIDv4 (
uuid.v4()) - Random. Best for general-purpose unique identifiers where unpredictability matters. - UUIDv8 (
uuid.v8(data)) - Custom. Create UUIDs from custom 16-byte data for specialized use cases. - Nil UUID (
uuid.nil_uuid()) - All zeros. Use to represent "no value".
Which Version to Use? #
For database primary keys: Use v7 (best index performance, sortable)
For distributed unique IDs: Use v4 (unpredictable, no coordination needed)
For deterministic IDs from names: Use v5 with appropriate namespace (same input = same UUID)
For timestamp-based IDs: Use v7 (modern) or v6 (legacy systems)
For custom binary data: Use v8
All UUID versions can be parsed from strings using uuid.parse().
Performance Notes #
- UUID generation is very fast (random number generation)
- UUID parsing is optimized for both hyphenated and simple formats
- UUIDs are 128 bits (16 bytes) in memory
- String representation is 36 bytes (with hyphens) or 32 bytes (without)
Best Practices #
- Use UUIDs for distributed systems where you need globally unique identifiers without coordination
- Choose the right version:
- Use v7 for database primary keys and when you need sortability
- Use v4 when you need unpredictability and have no ordering requirements
- Store as native UUID type in PostgreSQL rather than strings for better performance and indexing
- Use hyphenated format for display but consider simple format for API responses or compact storage
- Use v7 for time-series data - the built-in timestamp makes them perfect for logs, events, and audit trails
- Use nil UUID to represent "no value" rather than empty strings
See Also #
- Database Module - PostgreSQL integration with UUID support
- Bytes Type - Binary data representation
- String Type - String operations