Class: ReeMapper::DbLoadCompiler
- Inherits:
-
Object
- Object
- ReeMapper::DbLoadCompiler
- Defined in:
- lib/ree_lib/packages/ree_mapper/package/ree_mapper/db_load_compiler.rb
Overview
Compiles a specialized :db_load for composite mappers when Ree.db_load_performance_mode? is on at mapper build time.
The compiled method handles the hot call shape db_load(hash) with no
role/filters as straight-line per-field code: values of primitive types
skip casting behind a cheap type guard (see AbstractType#db_load_trusted_check),
non-trusted types (custom, enums, pg wrappers, nested mappers) are cast as
usual, and dto construction goes through a single attrs hash instead of
build-then-copy. Every other call shape falls back to the untouched generic
method, kept as __generic_db_load.
Codegen targets the mapper's anonymous class (each Mapper.build creates one), never the instance: registered mappers are frozen.
Class Method Summary collapse
Class Method Details
.compile(mapper) ⇒ Object
18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 |
# File 'lib/ree_lib/packages/ree_mapper/package/ree_mapper/db_load_compiler.rb', line 18 def compile(mapper) return if mapper.type # leaf mappers keep their generic delegation strategy = mapper.find_strategy(:db_load) return unless strategy case (output = strategy.output) when ReeMapper::ReeDtoOutput builder = "acc = {}" finisher = "DB_LOAD_DTO.build_from_attrs(acc)" when ReeMapper::HashOutput return unless strategy.dto == ::Hash # OpenStruct keeps the generic path builder = "acc = {}" finisher = "acc" when ReeMapper::ObjectOutput builder = "acc = DB_LOAD_DTO.allocate" finisher = "acc" else return # StructOutput and unknown outputs keep the generic path end klass = mapper.class return if klass.method_defined?(:__generic_db_load, false) # already compiled fields = mapper.fields.values set_const(klass, :DB_LOAD_FIELDS, fields.freeze) set_const(klass, :DB_LOAD_DTO, strategy.dto) set_const( klass, :DB_LOAD_NESTED_FILTERS, fields.map { _1.fields_filter ? [_1.fields_filter].freeze : nil }.freeze ) body = fields.each_with_index.filter_map { |field, idx| # the generic loop skips role-scoped fields when role is nil; calls # with an actual role go through the generic fallback next unless field.roles.empty? field_code(field, idx, output, strategy.always_optional) }.join("\n") klass.send(:alias_method, :__generic_db_load, :db_load) klass.class_eval(" def db_load(obj, role: nil, only: nil, except: nil, fields_filters: nil)\n if role || only || except || fields_filters || !obj.is_a?(::Hash)\n return __generic_db_load(obj, role: role, only: only, except: except, fields_filters: fields_filters)\n end\n\n \#{builder}\n \#{body}\n \#{finisher}\n end\n RUBY\n\n # keep the generated source inspectable for debugging\n klass.instance_variable_set(:@compiled_db_load_source, body)\n\n nil\nend\n", __FILE__, __LINE__ + 1) |