Module: Familia::Horreum::Serialization
- Included in:
- Familia::Horreum
- Defined in:
- lib/familia/horreum/serialization.rb
Overview
Serialization - Instance-level methods for object serialization Handles conversion between Ruby objects and Valkey hash storage
Instance Method Summary collapse
-
#deserialize_value(val, symbolize: false, field_name: nil) ⇒ Object
Converts a Redis string value back to its original Ruby type.
-
#serialize_value(val) ⇒ String
Serializes a Ruby object for Valkey storage.
-
#to_a ⇒ Array
Converts the object's persistent fields to an array.
-
#to_h ⇒ Hash
Converts the object's persistent fields to a hash for external use.
-
#to_h_for_storage ⇒ Hash
Converts the object's persistent fields to a hash for database storage.
Instance Method Details
#deserialize_value(val, symbolize: false, field_name: nil) ⇒ Object
Converts a Redis string value back to its original Ruby type
This method deserializes JSON strings back to their original Ruby types (Integer, Boolean, Float, nil, Hash, Array). Plain strings that cannot be parsed as JSON are returned as-is.
This pairs with serialize_value which JSON-encodes all non-string values. The contract ensures type preservation across Redis storage:
- Strings stored as-is → returned as-is
- All other types JSON-encoded → JSON-decoded back to original type
161 162 163 164 165 166 167 168 169 170 171 172 173 |
# File 'lib/familia/horreum/serialization.rb', line 161 def deserialize_value(val, symbolize: false, field_name: nil) return nil if val.nil? || val == '' # Handle Redis::Future objects during transactions return val if val.is_a?(Redis::Future) begin Familia::JsonSerializer.parse(val, symbolize_names: symbolize) rescue Familia::SerializerError log_deserialization_issue(val, field_name) val end end |
#serialize_value(val) ⇒ String
Strings are JSON-encoded to prevent type coercion bugs where string "123" would be indistinguishable from integer 123 in storage
This method integrates with Familia's type system and supports custom serialization methods when available on the object
Serializes a Ruby object for Valkey storage.
Converts ALL Ruby values (including strings) to JSON-encoded strings for type-safe storage. This ensures round-trip type preservation: the type you save is the type you get back.
The serialization process:
- ConcealedStrings (encrypted values) → extract encrypted_value
- ALL other types → JSON serialization (String, Integer, Boolean, Float, nil, Hash, Array)
136 137 138 139 140 141 142 143 |
# File 'lib/familia/horreum/serialization.rb', line 136 def serialize_value(val) # Security: Handle ConcealedString safely - extract encrypted data for storage return val.encrypted_value if val.respond_to?(:encrypted_value) # ALWAYS write valid JSON for type preservation # This includes strings, which get JSON-encoded with wrapping quotes Familia::JsonSerializer.dump(val) end |
#to_a ⇒ Array
Values are serialized using the same process as other persistence methods to maintain data consistency across operations.
Converts the object's persistent fields to an array.
Serializes all persistent field values in field definition order, preparing them for Valkey storage. Each value is processed through the serialization pipeline to ensure Valkey compatibility.
92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 |
# File 'lib/familia/horreum/serialization.rb', line 92 def to_a self.class.persistent_fields.map do |field| field_type = self.class.field_types[field] # Security: Skip non-loggable fields (e.g., encrypted fields) next unless field_type.loggable method_name = field_type.method_name val = send(method_name) Familia.debug " [to_a] field: #{field} method: #{method_name} val: #{val.class}" # Return actual Ruby values, including nil to maintain array positions val end end |
#to_h ⇒ Hash
Only loggable fields are included. Encrypted fields are excluded.
Nil values are excluded from the returned hash (storage optimization)
Converts the object's persistent fields to a hash for external use.
Returns actual Ruby values (String, Integer, Hash, etc.) for API consumption, NOT JSON-encoded strings. Excludes non-loggable fields like encrypted fields for security.
27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 |
# File 'lib/familia/horreum/serialization.rb', line 27 def to_h self.class.persistent_fields.each_with_object({}) do |field, hsh| field_type = self.class.field_types[field] # Security: Skip non-loggable fields (e.g., encrypted fields) next unless field_type.loggable val = send(field_type.method_name) Familia.debug " [to_h] field: #{field} val: #{val.class}" # Use string key for external API compatibility # Return Ruby values, not JSON-encoded strings hsh[field.to_s] = val end end |
#to_h_for_storage ⇒ Hash
This is an internal method used by commit_fields and hmset
Nil values are excluded to optimize Redis storage
Converts the object's persistent fields to a hash for database storage.
Returns JSON-encoded strings for ALL persistent field values, ready for Redis storage. Unlike to_h, this includes encrypted fields and serializes values using serialize_value (JSON encoding).
60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 |
# File 'lib/familia/horreum/serialization.rb', line 60 def to_h_for_storage self.class.persistent_fields.each_with_object({}) do |field, hsh| field_type = self.class.field_types[field] val = send(field_type.method_name) prepared = serialize_value(val) if Familia.debug? Familia.debug " [to_h_for_storage] field: #{field} val: #{val.class} prepared: #{prepared&.class || '[nil]'}" end # Use string key for database compatibility hsh[field.to_s] = prepared end end |