lib/avromatic/model/raw_serialization.rb in avromatic-0.23.0 vs lib/avromatic/model/raw_serialization.rb in avromatic-0.24.0
- old
+ new
@@ -13,24 +13,59 @@
delegate :avro_serializer, :datum_writer, :datum_reader, :attribute_set,
to: :class
private :avro_serializer, :datum_writer, :datum_reader
+ EMPTY_ARRAY = [].freeze
+
+ included do
+ @attribute_member_types = {}
+ end
+
module ClassMethods
- def recursive_serialize(value, attribute_name = nil)
+ def recursive_serialize(value, name: nil, member_types: nil)
+ member_types = attribute_member_types(name) if name
+ member_types ||= EMPTY_ARRAY
+
if value.is_a?(Avromatic::Model::Attributes)
- value.value_attributes_for_avro
+ hash = value.value_attributes_for_avro
+ if Avromatic.use_custom_datum_writer
+ member_index = member_types.index(value.class) if member_types.any?
+ hash[Avromatic::IO::UNION_MEMBER_INDEX] = member_index if member_index
+ end
+ hash
elsif value.is_a?(Array)
- value.map { |v| recursive_serialize(v) }
+ value.map { |v| recursive_serialize(v, member_types: member_types) }
elsif value.is_a?(Hash)
- value.each_with_object({}) do |(k, v), hash|
- hash[k] = recursive_serialize(v)
+ value.each_with_object({}) do |(k, v), map|
+ map[k] = recursive_serialize(v, member_types: member_types)
end
else
- avro_serializer[attribute_name].call(value)
+ avro_serializer[name].call(value)
end
end
+
+ private
+
+ def attribute_member_types(name)
+ @attribute_member_types.fetch(name) do
+ member_types = nil
+ attribute = attribute_set[name] if name
+ if attribute
+ if attribute.primitive == Array &&
+ attribute.member_type.is_a?(Avromatic::Model::Attribute::Union)
+ member_types = attribute.member_type.primitive.types
+ elsif attribute.primitive == Hash &&
+ attribute.value_type.is_a?(Avromatic::Model::Attribute::Union)
+ member_types = attribute.value_type.primitive.types
+ elsif attribute.options[:primitive] == Avromatic::Model::AttributeType::Union
+ member_types = attribute.primitive.types
+ end
+ end
+ @attribute_member_types[name] = member_types
+ end
+ end
end
def avro_raw_value
avro_raw_encode(value_attributes_for_avro, :value)
end
@@ -42,19 +77,19 @@
def value_attributes_for_avro
avro_hash(value_avro_field_names)
end
- private
-
def key_attributes_for_avro
avro_hash(key_avro_field_names)
end
+ private
+
def avro_hash(fields)
attributes.slice(*fields).each_with_object(Hash.new) do |(key, value), result|
- result[key.to_s] = self.class.recursive_serialize(value, key)
+ result[key.to_s] = self.class.recursive_serialize(value, name: key)
end
end
def avro_raw_encode(data, key_or_value = :value)
stream = StringIO.new
@@ -92,23 +127,27 @@
end
end
module ClassMethods
def datum_reader_class
- Avromatic::IO::DatumReader
+ Avromatic.use_custom_datum_reader ? Avromatic::IO::DatumReader : Avro::IO::DatumReader
end
+ def datum_writer_class
+ Avromatic.use_custom_datum_writer ? Avromatic::IO::DatumWriter : Avro::IO::DatumWriter
+ end
+
# Store a hash of Procs by field name (as a symbol) to convert
# the value before Avro serialization.
# Returns the default PassthroughSerializer if a key is not present.
def avro_serializer
@avro_serializer ||= Hash.new(PassthroughSerializer)
end
def datum_writer
@datum_writer ||= begin
- hash = { value: Avro::IO::DatumWriter.new(value_avro_schema) }
- hash[:key] = Avro::IO::DatumWriter.new(key_avro_schema) if key_avro_schema
+ hash = { value: datum_writer_class.new(value_avro_schema) }
+ hash[:key] = datum_writer_class.new(key_avro_schema) if key_avro_schema
hash
end
end
def datum_reader