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

Instance Method Details

#deserialize_value(val, symbolize: true) ⇒ Object

Converts a Database string value back to its original Ruby type

This method attempts to deserialize JSON strings back to their original Hash or Array types. Simple string values are returned as-is.

Parameters:

  • val (String)

    The string value from Database to deserialize

  • symbolize (Boolean) (defaults to: true)

    Whether to symbolize hash keys (default: true for compatibility)

Returns:

  • (Object)

    The deserialized value (Hash, Array, or original string)



155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
# File 'lib/familia/horreum/serialization.rb', line 155

def deserialize_value(val, symbolize: true)
  return val if val.nil? || val == ''

  # Try to parse as JSON first for complex types
  begin
    parsed = Familia::JsonSerializer.parse(val, symbolize_names: symbolize)
    # Only return parsed value if it's a complex type (Hash/Array)
    # Simple values should remain as strings
    return parsed if parsed.is_a?(Hash) || parsed.is_a?(Array)
  rescue Familia::SerializerError
    # Not valid JSON, return as-is
  end

  val
end

#serialize_value(val) ⇒ String?

Note:

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 Ruby objects into the DB-compatible string representations using the Familia distinguisher for type coercion. Falls back to JSON serialization for complex types (Hash, Array) when the primary distinguisher returns nil.

The serialization process:

  1. Attempts conversion using Familia.distinguisher with relaxed type checking
  2. For Hash/Array types that return nil, tries custom dump_method or Familia::JsonSerializer.dump
  3. Logs warnings when serialization fails completely

Examples:

Serializing different data types

serialize_value("hello")        # => "hello"
serialize_value(42)             # => "42"
serialize_value({name: "John"}) # => '{"name":"John"}'
serialize_value([1, 2, 3])      # => "[1,2,3]"

Parameters:

  • val (Object)

    The Ruby object to serialize for Valkey storage

Returns:

  • (String, nil)

    The serialized value ready for Valkey storage, or nil if serialization failed

See Also:

  • The primary serialization mechanism


128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
# File 'lib/familia/horreum/serialization.rb', line 128

def serialize_value(val)
  # Security: Handle ConcealedString safely - extract encrypted data for storage
  return val.encrypted_value if val.respond_to?(:encrypted_value)

  prepared = Familia.distinguisher(val, strict_values: false)

  # If the distinguisher returns nil, try using the dump_method but only
  # use JSON serialization for complex types that need it.
  if prepared.nil? && (val.is_a?(Hash) || val.is_a?(Array))
    prepared = val.respond_to?(dump_method) ? val.send(dump_method) : Familia::JsonSerializer.dump(val)
  end

  # If both the distinguisher and dump_method return nil, log an error
  Familia.ld "[#{self.class}#serialize_value] nil returned for #{self.class}" if prepared.nil?

  prepared
end

#to_aArray

Note:

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.

Examples:

Converting an object to array format

user = User.new(name: "John", email: "john@example.com", age: 30)
user.to_a
# => ["John", "john@example.com", "30"]

Returns:

  • (Array)

    Array of serialized field values in field order



86
87
88
89
90
91
92
93
94
95
96
97
98
99
# File 'lib/familia/horreum/serialization.rb', line 86

def to_a
  self.class.persistent_fields.filter_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)
    prepared = serialize_value(val)
    Familia.ld " [to_a] field: #{field} method: #{method_name} val: #{val.class} prepared: #{prepared.class}"
    prepared
  end
end

#to_hHash

Note:

Only loggable fields are included for security

Note:

Only fields with non-nil values are included

Converts the object's persistent fields to a hash for external use.

Serializes persistent field values for external consumption (APIs, logs), excluding non-loggable fields like encrypted fields for security. Only non-nil values are included in the resulting hash.

Examples:

Converting an object to hash format for API response

user = User.new(name: "John", email: "john@example.com", age: 30)
user.to_h
# => {"name"=>"John", "email"=>"john@example.com", "age"=>"30"}
# encrypted fields are excluded for security

Returns:

  • (Hash)

    Hash with field names as keys and serialized values safe for external exposure



26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
# File 'lib/familia/horreum/serialization.rb', line 26

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

    method_name = field_type.method_name
    val = send(method_name)
    prepared = serialize_value(val)
    Familia.ld " [to_h] field: #{field} val: #{val.class} prepared: #{prepared&.class || '[nil]'}"

    # Only include non-nil values in the hash for Valkey
    # Use string key for database compatibility
    hsh[field.to_s] = prepared unless prepared.nil?
  end
end

#to_h_for_storageHash

Note:

Includes ALL persistent fields, including encrypted fields

Note:

Only fields with non-nil values are included for storage efficiency

Converts the object's persistent fields to a hash for database storage.

Serializes ALL persistent field values for database storage, including encrypted fields. This is used internally by commit_fields and other persistence operations.

Returns:

  • (Hash)

    Hash with field names as keys and serialized values ready for database storage



56
57
58
59
60
61
62
63
64
65
66
67
68
# File 'lib/familia/horreum/serialization.rb', line 56

def to_h_for_storage
  self.class.persistent_fields.each_with_object({}) do |field, hsh|
    field_type = self.class.field_types[field]
    method_name = field_type.method_name
    val = send(method_name)
    prepared = serialize_value(val)
    Familia.ld " [to_h_for_storage] field: #{field} val: #{val.class} prepared: #{prepared&.class || '[nil]'}"

    # Only include non-nil values in the hash for Valkey
    # Use string key for database compatibility
    hsh[field.to_s] = prepared unless prepared.nil?
  end
end