Module: Familia::DataType::Serialization
- Included in:
- Familia::DataType
- Defined in:
- lib/familia/data_type/serialization.rb
Instance Method Summary collapse
-
#deserialize_value(val) ⇒ Object?
Deserializes a single value from the database.
-
#deserialize_values(*values) ⇒ Array<Object>
Deserializes multiple values from Valkey/Redis, removing nil values.
-
#deserialize_values_with_nil(*values) ⇒ Array<Object, nil>
Deserializes multiple values from Valkey/Redis, preserving nil values.
-
#serialize_value(val) ⇒ String
Serializes a value for storage in the database.
Instance Method Details
#deserialize_value(val) ⇒ Object?
Deserializes a single value from the database.
Deserialization priority:
- Redis::Future objects → return as-is (transaction handling)
- nil values → return default option value
- Class option specified → use class-based deserialization
- No class option → JSON parse for type preservation
This unifies behavior with Horreum fields (Issue #190), ensuring consistent type preservation. Legacy data stored without JSON encoding is returned as-is.
149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 |
# File 'lib/familia/data_type/serialization.rb', line 149 def deserialize_value(val) # Handle Redis::Future objects during transactions first return val if val.is_a?(Redis::Future) return @opts[:default] if val.nil? # Reference collections store raw identifiers — return as-is return val if @opts[:reference] # If a class option is specified, use the existing class-based deserialization if @opts[:class] ret = deserialize_values val return ret&.first # return the object or nil end # No class option: JSON deserialize for type preservation (Issue #190) # This unifies behavior with Horreum fields begin Familia::JsonSerializer.parse(val) rescue Familia::SerializerError Familia.warn "[deserialize] Raw fallback in #{dbkey} (#{val.class}, #{val.respond_to?(:bytesize) ? val.bytesize : '?'} bytes)" val end end |
#deserialize_values(*values) ⇒ Array<Object>
Deserializes multiple values from Valkey/Redis, removing nil values.
69 70 71 72 73 74 75 |
# File 'lib/familia/data_type/serialization.rb', line 69 def deserialize_values(*values) # Avoid using compact! here. Using compact! as the last expression in the # method can unintentionally return nil if no changes are made, which is # not desirable. Instead, use compact to ensure the method returns the # expected value. deserialize_values_with_nil(*values).compact end |
#deserialize_values_with_nil(*values) ⇒ Array<Object, nil>
This method attempts to deserialize each value using the specified class's from_json method. If deserialization fails for a value, it's replaced with nil.
Deserializes multiple values from Valkey/Redis, preserving nil values.
88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 |
# File 'lib/familia/data_type/serialization.rb', line 88 def deserialize_values_with_nil(*values) Familia.debug "deserialize_values: (#{@opts}) #{values}" return [] if values.empty? # Reference collections store raw identifiers — return as-is if @opts[:reference] return values.flatten end # If a class option is specified, use class-based deserialization if @opts[:class] unless @opts[:class].respond_to?(:from_json) raise Familia::Problem, "No such method: #{@opts[:class]}.from_json" end values.collect! do |obj| next if obj.nil? val = @opts[:class].from_json(obj) Familia.debug "[#{self.class}#deserialize_values] nil returned for #{@opts[:class]}.from_json" if val.nil? val rescue StandardError => e Familia.debug "[deserialize] from_json error in #{dbkey}: #{e.}" Familia.debug " raw value: #{obj.inspect[0..80]}" Familia.trace :DESERIALIZE_ERROR, dbkey, e. if Familia.debug? nil end return values end # No class option: JSON deserialize each value for type preservation (Issue #190) values.flatten.collect do |obj| next if obj.nil? begin Familia::JsonSerializer.parse(obj) rescue Familia::SerializerError Familia.debug "[deserialize] Raw fallback in #{dbkey}: #{obj.inspect[0..80]}" obj end end end |
#serialize_value(val) ⇒ String
Serializes a value for storage in the database.
Serialization priority:
- Familia objects (Base instances or classes) → extract identifier
- All other values → JSON serialize for type preservation
This unifies behavior with Horreum fields (Issue #190), ensuring consistent type preservation across DataType and Horreum.
30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 |
# File 'lib/familia/data_type/serialization.rb', line 30 def serialize_value(val) Familia.trace :TOREDIS, nil, "#{val}<#{val.class}|#{opts[:class]}>" if Familia.debug? # Priority 1: Handle Familia object references - extract identifier # This preserves the existing behavior for storing object references if val.is_a?(Familia::Base) || (val.is_a?(Class) && val.ancestors.include?(Familia::Base)) prepared = val.is_a?(Class) ? val.name : val.identifier Familia.debug " Familia object: #{val.class} => #{prepared}" return prepared end # Priority 1b: If this collection stores object references (reference: true) # and the value is a String, treat it as a raw identifier. This prevents # mismatches when callers pass identifier strings directly instead of # Familia objects. if val.is_a?(String) && opts[:reference] Familia.debug " String identifier (reference): #{val}" return val end # Priority 2: Everything else gets JSON serialized for type preservation # This unifies behavior with Horreum fields (Issue #190) prepared = Familia::JsonSerializer.dump(val) Familia.debug " JSON serialized: #{val.class} => #{prepared}" if Familia.debug? Familia.trace :TOREDIS, nil, "#{val}<#{val.class}> => #{prepared}<#{prepared.class}>" end prepared end |