aglushkov/serega

View on GitHub
lib/serega/plugins/preloads/lib/preloads_constructor.rb

Summary

Maintainability
A
1 hr
Test Coverage
A
100%
# frozen_string_literal: true

class Serega
  module SeregaPlugins
    module Preloads
      #
      # Finds preloads for provided attributes plan
      #
      class PreloadsConstructor
        class << self
          #
          # Constructs preloads hash for given attributes plan
          #
          # @param plan [Array<SeregaPlanPoint>] Serialization plan
          #
          # @return [Hash]
          #
          def call(plan)
            return FROZEN_EMPTY_HASH unless plan

            preloads = {}
            append_many(preloads, plan)
            preloads
          end

          private

          def append_many(preloads, plan)
            plan.points.each do |point|
              current_preloads = point.attribute.preloads
              next unless current_preloads

              child_plan = point.child_plan
              current_preloads = SeregaUtils::EnumDeepDup.call(current_preloads) if child_plan
              append_current(preloads, current_preloads)
              next unless child_plan

              each_child_preloads(preloads, point.preloads_path) do |child_preloads|
                append_many(child_preloads, child_plan)
              end
            end
          end

          def append_current(preloads, current_preloads)
            merge(preloads, current_preloads) unless current_preloads.empty?
          end

          def merge(preloads, current_preloads)
            preloads.merge!(current_preloads) do |_key, value_one, value_two|
              merge(value_one, value_two)
            end
          end

          def each_child_preloads(preloads, preloads_path)
            return yield(preloads) if preloads_path.nil?

            if preloads_path[0].is_a?(Array)
              preloads_path.each do |path|
                yield dig_fetch(preloads, path)
              end
            else
              yield dig_fetch(preloads, preloads_path)
            end
          end

          def dig_fetch(preloads, preloads_path)
            return preloads if !preloads_path || preloads_path.empty?

            preloads_path.each do |path|
              preloads = preloads.fetch(path)
            end

            preloads
          end
        end
      end
    end
  end
end