diff --git a/ree_lib/lib/ree_lib/packages/ree_mapper/package/ree_mapper/mapper.rb b/ree_lib/lib/ree_lib/packages/ree_mapper/package/ree_mapper/mapper.rb index 5a1fd0a0..12a11c3b 100644 --- a/ree_lib/lib/ree_lib/packages/ree_mapper/package/ree_mapper/mapper.rb +++ b/ree_lib/lib/ree_lib/packages/ree_mapper/package/ree_mapper/mapper.rb @@ -1,6 +1,8 @@ # frozen_string_literal: true class ReeMapper::Mapper + EMPTY_ARY = [].freeze + contract( ArrayOf[ReeMapper::MapperStrategy], Nilor[ReeMapper::AbstractType, ReeMapper::AbstractWrapper] => self @@ -23,7 +25,7 @@ def self.build(strategies, type = nil) if type class_eval(<<~RUBY, __FILE__, __LINE__ + 1) - def #{method}(obj, name: nil, role: nil, only: nil, except: nil, fields_filters: [], location: nil) + def #{method}(obj, name: nil, role: nil, only: nil, except: nil, fields_filters: EMPTY_ARY, location: nil) #{ if type.is_a?(ReeMapper::AbstractWrapper) "@type.#{method}(obj, name: name, role: role, fields_filters: fields_filters, location: location)" @@ -35,7 +37,7 @@ def #{method}(obj, name: nil, role: nil, only: nil, except: nil, fields_filters: RUBY else class_eval(<<~RUBY, __FILE__, __LINE__ + 1) - def #{method}(obj, name: nil, role: nil, only: nil, except: nil, fields_filters: [], location: nil) + def #{method}(obj, name: nil, role: nil, only: nil, except: nil, fields_filters: EMPTY_ARY, location: nil) if only && !ReeMapper::FilterFieldsContract.valid?(only) raise ReeMapper::ArgumentError, "Invalid `only` format" end @@ -47,7 +49,11 @@ def #{method}(obj, name: nil, role: nil, only: nil, except: nil, fields_filters: user_fields_filter = ReeMapper::FieldsFilter.build(only: only, except: except) @fields.each_with_object(@#{method}_strategy.build_object) do |(_, field), acc| - field_fields_filters = fields_filters + [user_fields_filter] + field_fields_filters = if user_fields_filter == ReeMapper::FieldsFilter::NoneStrategy + fields_filters + else + fields_filters + [user_fields_filter] + end next unless field_fields_filters.all? { _1.allow? field.name } next unless field.has_role?(role) @@ -56,7 +62,10 @@ def #{method}(obj, name: nil, role: nil, only: nil, except: nil, fields_filters: is_optional = field.optional || @#{method}_strategy.always_optional if !is_with_value && !is_optional - raise ReeMapper::TypeError.new("Missing required field `\#{field.from_as_str}` for `\#{name || 'root'}`", field.location) + raise ReeMapper::TypeError.new( + "Missing required field `\#{field.from_as_str}` for `\#{name || 'root'}`", + field.location + ) end next if !is_with_value && !field.has_default? @@ -70,8 +79,15 @@ def #{method}(obj, name: nil, role: nil, only: nil, except: nil, fields_filters: unless value.nil? && field.null nested_name = name ? "\#{name}[\#{field.name_as_str}]" : field.name_as_str - nested_fields_filters = field_fields_filters.map { _1.filter_for(field.name) } - nested_fields_filters += [field.fields_filter] + nested_fields_filters = if field_fields_filters.empty? + field_fields_filters + else + field_fields_filters.map { _1.filter_for(field.name) } + end + + if field.fields_filter != ReeMapper::FieldsFilter::NoneStrategy + nested_fields_filters += [field.fields_filter] + end value = field.type.#{method}( value, diff --git a/ree_lib/lib/ree_lib/packages/ree_mapper/spec/ree_mapper/benchmarks/mapper_benchmark_spec.rb b/ree_lib/lib/ree_lib/packages/ree_mapper/spec/ree_mapper/benchmarks/mapper_benchmark_spec.rb new file mode 100644 index 00000000..39b2d2c1 --- /dev/null +++ b/ree_lib/lib/ree_lib/packages/ree_mapper/spec/ree_mapper/benchmarks/mapper_benchmark_spec.rb @@ -0,0 +1,31 @@ +# frozen_string_literal: true +require 'benchmark' + +package_require "ree_mapper" + +RSpec.xdescribe 'Mapper Benchmark' do + link :build_mapper_factory, from: :ree_mapper + link :build_mapper_strategy, from: :ree_mapper + + let(:mapper) do + build_mapper_factory( + strategies: [ + build_mapper_strategy(method: :cast, dto: Hash), + ] + ).call.use(:cast) do + hash :my_field do + hash :my_field do + integer :my_field + end + end + end + end + + it do + obj = { my_field: { my_field: { my_field: 1 } } } + + _benchmark_res = Benchmark.bmbm do |x| + x.report('cast') { 1000.times { mapper.cast(obj) } } + end + end +end