calismamasam/calismamasam.com

View on GitHub
app/interactors/stats_interactors/get_chart_data.rb

Summary

Maintainability
A
3 hrs
Test Coverage
module StatsInteractors
  class GetChartData
    include Interactor

    def call
      # Get products
      category_ids = context.parent_product_category ? context.parent_product_category.subtree.map(&:subtree_ids).flatten.uniq : nil
      products = Product.where(category_id: category_ids)
      if context.post_category.present?
        products = products.where(id: context.post_category.posts.active.map { |post| post.products.pluck(:product_id) }.flatten)
      end
      context.products = products

      # Set product ids
      context.product_ids = products.pluck(:id)

      # Group products by categories
      if products.any?
        records = ActiveRecord::Base.connection.execute(raw_query(products.pluck(:id).join(',')))
        total_records = ActiveRecord::Base.connection.execute(raw_query_for_total_count(products.pluck(:id).join(',')))
        total_count = total_records.class == Array ? total_records[0][0] : total_records.values[0][0]
      else
        records = []
        total_count = 0
      end

      # Set products for chart
      percentages = 0
      chart_array = records.map do |k|
        k = k.values.map(&:to_i)
        product = Product.find(k[1])
        next unless product
        percentage = ((k[0].to_f / total_count.to_f) * 100).round(2)
        next if percentage < 1.0
        percentages += percentage
        title = "#{product.decorate.name_with_brand} (#{percentage}%)"
        [title, k[0]]
      end
      chart_array = chart_array.compact
      sum_of_products = chart_array.inject(0) { |sum, x| sum + x[1] }
      if total_count.to_i > sum_of_products.to_i
        percentage = (100.00 - percentages).round(2)
        chart_array << ["Diğer (#{percentage})", total_count.to_i - sum_of_products.to_i]
      end
      context.chart_data = chart_array
    end


    private

    def raw_query(product_ids)
      %|
        SELECT COUNT(*) AS count_all, product_id
        FROM posts_products
        WHERE product_id in (#{product_ids})
        GROUP BY product_id
        ORDER BY count_all DESC, product_id;
      |
    end

    def raw_query_for_total_count(product_ids)
      %|
        SELECT COUNT(*)
        FROM posts_products
        WHERE product_id in (#{product_ids})
      |
    end
  end
end