Skip to content

Commit

Permalink
Merge pull request #98 from belousovAV/36-optimize-mapper-fields-filter
Browse files Browse the repository at this point in the history
Optimize mapper fields filter
  • Loading branch information
rous-gg committed Jan 25, 2024
2 parents 94c1200 + 2a97ab7 commit 3ed7dc6
Show file tree
Hide file tree
Showing 2 changed files with 53 additions and 6 deletions.
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
# frozen_string_literal: true

class ReeMapper::Mapper
EMPTY_ARY = [].freeze

contract(
ArrayOf[ReeMapper::MapperStrategy],
Nilor[ReeMapper::AbstractType, ReeMapper::AbstractWrapper] => self
Expand All @@ -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)"
Expand All @@ -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
Expand All @@ -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)
Expand All @@ -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?
Expand All @@ -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,
Expand Down
Original file line number Diff line number Diff line change
@@ -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

0 comments on commit 3ed7dc6

Please sign in to comment.