Module: Familia::Features::ObjectIdentifier

Defined in:
lib/familia/features/object_identifier.rb

Overview

ObjectIdentifier is a feature that provides unique object identifier management with configurable generation strategies. Object identifiers are crucial for distinguishing objects in distributed systems and providing stable references.

Object identifiers are:

  • Unique across the system
  • Persistent (stored in Valkey/Redis)
  • Lazily generated (only when first accessed)
  • Configurable (multiple generation strategies available)
  • Preserved during initialization (existing IDs never regenerated)

Generation Strategies:

  • :uuid_v7 (default) - UUID version 7 with embedded timestamp for sortability
  • :uuid_v4 - UUID version 4 for compatibility with legacy systems
  • :hex - High-entropy hexadecimal identifier using SecureIdentifier
  • Proc - Custom generation logic provided as a callable

Example Usage:

# Default UUID v7 generation class User < Familia::Horreum feature :object_identifier field :email end

user = User.new(email: 'user@example.com') user.objid # => "01234567-89ab-7def-8000-123456789abc" (UUID v7)

# UUID v4 for legacy compatibility class LegacyUser < Familia::Horreum feature :object_identifier, generator: :uuid_v4 field :email end

legacy = LegacyUser.new(email: 'legacy@example.com') legacy.objid # => "f47ac10b-58cc-4372-a567-0e02b2c3d479" (UUID v4)

# High-entropy hex for security-sensitive applications class SecureDocument < Familia::Horreum feature :object_identifier, generator: :hex field :title end

doc = SecureDocument.new(title: 'Classified') doc.objid # => "a1b2c3d4e5f6..." (256-bit hex)

# Custom generation strategy class TimestampedItem < Familia::Horreum feature :object_identifier, generator: -> { "item_#Familia.now.to_i_#SecureRandom.hex(4)" } field :data end

item = TimestampedItem.new(data: 'test') item.objid # => "item_1693857600_a1b2c3d4"

Data Integrity Guarantees:

The feature preserves the object identifier passed during initialization, ensuring that existing objects loaded from Valkey/Redis maintain their IDs:

# Loading existing object from Valkey/Redis preserves ID existing = User.new(objid: 'existing-uuid-value', email: 'existing@example.com') existing.objid # => "existing-uuid-value" (preserved, not regenerated)

Performance Characteristics:

  • Lazy Generation: IDs generated only when first accessed
  • Thread-Safe: Generator strategy configured once during initialization
  • Memory Efficient: No unnecessary ID generation for unused objects
  • Valkey/Redis Efficient: Only persists non-nil values to conserve memory

Security Considerations:

  • UUID v7 includes timestamp information (may leak timing data)
  • UUID v4 provides strong randomness without timing correlation
  • Hex generator provides maximum entropy (256 bits) for security-critical use cases
  • Custom generators allow domain-specific security requirements

Defined Under Namespace

Modules: ModelClassMethods Classes: ObjectIdentifierFieldType

Constant Summary collapse

DEFAULT_GENERATOR =
:uuid_v7

Instance Method Summary collapse

Instance Method Details

#destroy!Object



315
316
317
318
319
320
321
322
# File 'lib/familia/features/object_identifier.rb', line 315

def destroy!
  # Clean up objid mapping when object is destroyed
  current_objid = instance_variable_get(:@objid)

  self.class.objid_lookup.remove_field(current_objid) if current_objid

  super if defined?(super)
end

#initObject

Initialize object identifier configuration

Called during object initialization to set up the ID generation strategy. This hook is called AFTER field initialization, ensuring that any objid values passed during construction are preserved.



330
331
332
333
334
335
336
337
338
339
340
341
342
# File 'lib/familia/features/object_identifier.rb', line 330

def init
  super if defined?(super)

  # The generator strategy is configured at the class level via feature options.
  # We don't need to store it per-instance since it's consistent for the class.
  # The actual generation happens lazily in the getter when needed.

  return unless Familia.debug?

  options = self.class.feature_options(:object_identifier)
  generator = options[:generator] || DEFAULT_GENERATOR
  Familia.trace :OBJID_INIT, nil, "Generator strategy: #{generator}"
end

#object_identifierString

Full-length alias for objid for clarity when needed

Returns:

  • (String)

    The object identifier



303
304
305
# File 'lib/familia/features/object_identifier.rb', line 303

def object_identifier
  objid
end

#object_identifier=(value) ⇒ Object

Full-length alias setter for objid

Parameters:

  • value (String)

    The object identifier to set



311
312
313
# File 'lib/familia/features/object_identifier.rb', line 311

def object_identifier=(value)
  self.objid = value
end