lib/avromatic/model/raw_serialization.rb in avromatic-1.0.0 vs lib/avromatic/model/raw_serialization.rb in avromatic-2.0.0

- old
+ new

@@ -1,6 +1,6 @@ -require 'avromatic/model/passthrough_serializer' +# frozen_string_literal: true module Avromatic module Model # This module provides serialization support for encoding directly to Avro @@ -9,112 +9,56 @@ extend ActiveSupport::Concern module Encode extend ActiveSupport::Concern - delegate :avro_serializer, :datum_writer, :datum_reader, :attribute_set, - to: :class - private :avro_serializer, :datum_writer, :datum_reader + delegate :datum_writer, :datum_reader, to: :class + private :datum_writer, :datum_reader - EMPTY_ARRAY = [].freeze - - included do - @attribute_member_types = {} - end - - module ClassMethods - def recursive_serialize(value, name: nil, member_types: nil, strict: false) # rubocop:disable Lint/ShadowedArgument - member_types = attribute_member_types(name) if name - member_types ||= EMPTY_ARRAY - - if value.is_a?(Avromatic::Model::Attributes) - hash = strict ? value.avro_value_datum : value.value_attributes_for_avro - if !strict && Avromatic.use_custom_datum_writer - if Avromatic.use_encoding_providers? && !value.class.config.mutable - # n.b. Ideally we'd just return value here instead of wrapping it in a - # hash but then we'd have no place to stash the union member index... - hash = { Avromatic::IO::ENCODING_PROVIDER => value } - end - 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, member_types: member_types, strict: strict) } - elsif value.is_a?(Hash) - value.each_with_object({}) do |(k, v), map| - map[k] = recursive_serialize(v, member_types: member_types, strict: strict) - end - else - 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 + def avro_raw_value(validate: true) if self.class.config.mutable - avro_raw_encode(value_attributes_for_avro, :value) + avro_raw_encode(value_attributes_for_avro(validate: validate), :value) else - @avro_raw_value ||= avro_raw_encode(value_attributes_for_avro, :value) + @avro_raw_value ||= avro_raw_encode(value_attributes_for_avro(validate: validate), :value) end end - def avro_raw_key + def avro_raw_key(validate: true) raise 'Model has no key schema' unless key_avro_schema - avro_raw_encode(key_attributes_for_avro, :key) + avro_raw_encode(key_attributes_for_avro(validate: validate), :key) end - def value_attributes_for_avro + def value_attributes_for_avro(validate: true) if self.class.config.mutable - avro_hash(value_avro_field_names) + avro_hash(value_avro_field_names, validate: validate) else - @value_attributes_for_avro ||= avro_hash(value_avro_field_names) + @value_attributes_for_avro ||= avro_hash(value_avro_field_names, validate: validate) end end - def key_attributes_for_avro - avro_hash(key_avro_field_names) + def key_attributes_for_avro(validate: true) + avro_hash(key_avro_field_names, validate: validate) end - def avro_value_datum + def avro_value_datum(validate: true) if self.class.config.mutable - avro_hash(value_avro_field_names, strict: true) + avro_hash(value_avro_field_names, strict: true, validate: validate) else - @avro_datum ||= avro_hash(value_avro_field_names, strict: true) + @avro_datum ||= avro_hash(value_avro_field_names, strict: true, validate: validate) end end - def avro_key_datum - avro_hash(key_avro_field_names, strict: true) + def avro_key_datum(validate: true) + avro_hash(key_avro_field_names, strict: true, validate: validate) end private - def avro_hash(fields, strict: false) + def avro_hash(fields, strict: false, validate:) + avro_validate! if validate attributes.slice(*fields).each_with_object(Hash.new) do |(key, value), result| - result[key.to_s] = self.class.recursive_serialize(value, name: key, strict: strict) + result[key.to_s] = attribute_definitions[key].serialize(value, strict: strict) end end def avro_raw_encode(data, key_or_value = :value) stream = StringIO.new @@ -157,16 +101,9 @@ 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: datum_writer_class.new(value_avro_schema) }