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, ModelInstanceMethods Classes: ObjectIdentifierFieldType
Constant Summary collapse
- DEFAULT_GENERATOR =
:uuid_v7
Instance Method Summary collapse
- #destroy! ⇒ Object
-
#init ⇒ Object
Initialize object identifier configuration.
-
#object_identifier ⇒ String
Full-length alias for objid for clarity when needed.
- #object_identifier=(value) ⇒ Object
Instance Method Details
#destroy! ⇒ Object
436 437 438 439 440 441 442 443 |
# File 'lib/familia/features/object_identifier.rb', line 436 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 |
#init ⇒ Object
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.
451 452 453 454 455 456 457 458 459 460 461 462 463 |
# File 'lib/familia/features/object_identifier.rb', line 451 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? = self.class.(:object_identifier) generator = [:generator] || DEFAULT_GENERATOR Familia.trace :OBJID_INIT, nil, "Generator strategy: #{generator}" end |
#object_identifier ⇒ String
Full-length alias for objid for clarity when needed
395 396 397 |
# File 'lib/familia/features/object_identifier.rb', line 395 def object_identifier objid end |
#object_identifier=(value) ⇒ Object
432 433 434 |
# File 'lib/familia/features/object_identifier.rb', line 432 def object_identifier=(value) self.objid = value end |