Class: Familia::Features::ObjectIdentifier::ObjectIdentifierFieldType
- Inherits:
-
Familia::FieldType
- Object
- Familia::FieldType
- Familia::Features::ObjectIdentifier::ObjectIdentifierFieldType
- Defined in:
- lib/familia/features/object_identifier.rb
Overview
ObjectIdentifierFieldType - Generate a unique object identifier
Object identifier fields automatically generate unique identifiers when first accessed if not already set. The generation strategy is configurable via feature options. These fields preserve any values set during initialization to ensure data integrity when loading existing objects from the database.
The field type tracks the generator used for each objid to provide provenance information for security-sensitive operations like external identifier generation. This ensures that downstream features can validate the source and format of object identifiers without relying on string pattern matching, which cannot reliably distinguish between uuid7, uuid4, or hex formats in all cases.
Instance Method Summary collapse
-
#category ⇒ Symbol
Category for object identifier fields.
-
#define_getter(klass) ⇒ Object
Override getter to provide lazy generation with configured strategy.
-
#define_setter(klass) ⇒ Object
Override setter to preserve values during initialization.
-
#persistent? ⇒ Boolean
Object identifier fields are persisted to database.
Constructor Details
This class inherits a constructor from Familia::FieldType
Instance Method Details
#category ⇒ Symbol
Category for object identifier fields
225 226 227 |
# File 'lib/familia/features/object_identifier.rb', line 225 def category :object_identifier end |
#define_getter(klass) ⇒ Object
Override getter to provide lazy generation with configured strategy
Generates the identifier using the configured strategy if not already set. This preserves any values set during initialization while providing automatic generation for new objects.
144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 |
# File 'lib/familia/features/object_identifier.rb', line 144 def define_getter(klass) field_name = @name method_name = @method_name handle_method_conflict(klass, method_name) do klass.define_method method_name do # Check if we already have a value (from initialization or previous generation) existing_value = instance_variable_get(:"@#{field_name}") return existing_value unless existing_value.nil? # Generate new identifier using configured strategy generated_id = generate_object_identifier instance_variable_set(:"@#{field_name}", generated_id) # Track which generator was used for provenance = self.class.(:object_identifier) generator = [:generator] || DEFAULT_GENERATOR instance_variable_set(:"@#{field_name}_generator_used", generator) # Update mapping from objid to model primary key self.class.objid_lookup[generated_id] = identifier if respond_to?(:identifier) && identifier generated_id end end # Define getter for generator provenance tracking handle_method_conflict(klass, :"#{method_name}_generator_used") do klass.define_method :"#{method_name}_generator_used" do instance_variable_get(:"@#{field_name}_generator_used") end end end |
#define_setter(klass) ⇒ Object
Override setter to preserve values during initialization
This ensures that values passed during object initialization (e.g., when loading from Valkey/Redis) are preserved and not overwritten by the lazy generation logic.
186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 |
# File 'lib/familia/features/object_identifier.rb', line 186 def define_setter(klass) field_name = @name method_name = @method_name handle_method_conflict(klass, :"#{method_name}=") do klass.define_method :"#{method_name}=" do |value| # Remove old mapping if objid is changing old_value = instance_variable_get(:"@#{field_name}") if old_value && old_value != value Familia.logger.info("Removing objid mapping for #{old_value}") self.class.objid_lookup.remove_field(old_value) end instance_variable_set(:"@#{field_name}", value) # Update mapping from objid to this new identifier self.class.objid_lookup[value] = identifier unless value.nil? || identifier.nil? # When setting objid from external source (e.g., loading from Valkey/Redis), # we cannot determine the original generator, so we clear the provenance # tracking to indicate unknown origin. This prevents false assumptions # about the security properties of externally-provided identifiers. instance_variable_set(:"@#{field_name}_generator_used", nil) end end end |
#persistent? ⇒ Boolean
Object identifier fields are persisted to database
217 218 219 |
# File 'lib/familia/features/object_identifier.rb', line 217 def persistent? true end |