module Eco module API class Session class Batch # @attr_reader count [Integer] the total number of requests # @attr_reader stats [Hash] plain `Hash` with the number of requests that include an attribute class RequestStats CORE_ATTRS = Eco::API::Common::People::PersonParser::CORE_ATTRS ACCOUNT_ATTRS = (Eco::API::Common::People::PersonParser::ACCOUNT_ATTRS + ["permissions_custom"]).uniq DETAILS_ATTRS = ["fields"] class << self def valid_type?(type) Eco::API::Session::Batch::Job.valid_type?(type.to_sym) end def core_attrs(stats: false, all: false) CORE_ATTRS.dup.tap do |attrs| attrs.unshift("core") if stats || all end end def account_attrs(stats: false, all: false) ACCOUNT_ATTRS.dup.tap do |attrs| if stats || all attrs.unshift("account_remove") attrs.unshift("account") if all end end end def details_attrs(stats: false, all: false) DETAILS_ATTRS.dup.tap do |attrs| if stats || all attrs.unshift("details_remove") attrs.unshift("details") if all end end end end attr_reader :type, :count def initialize(type:, requests: []) raise "type should be one of #{Eco::API::Session::Batch::Job.types}. Given: #{type}" unless self.class.valid_type?(type.to_sym) @type = type.to_sym @count = requests && requests.length @stats = build(requests) end def to_h @stats end def core_attrs @core_attrs ||= self.class.core_attrs end def account_attrs @account_attrs ||= self.class.account_attrs end def details_attrs @details_attrs ||= self.class.details_attrs end def attr(attr, percent: false, total: count) i = @stats["#{attr}"] return i unless percent percentage(i, total: total) end def core(percent: false) attr("core", percent: percent) end def account(percent: false) attr("account", percent: percent) end def account_remove(percent: false) attr("account_remove", percent: percent) end def details(percent: false) attr("details", percent: percent) end def details_remove(percent: false) attr("details_remove", percent: percent) end def fields_average if (fields_num = attr("fields")) && (total = details) > 0 (fields_num.to_f / total.to_f).round(2) end end def message(percent: false) key_val_delimiter = ": "; attr_delimiter = " ++ " pairs_to_line = Proc.new do |pairs| pairs.map do |p| [p.first.to_s, "#{p.last.to_s}" + (percent ? "%" : "")].join(key_val_delimiter) end.join(attr_delimiter) end lines = [] lines << pairs_to_line.call(core_pairs(percent: percent)) lines << pairs_to_line.call(account_pairs(percent: percent)) lines << pairs_to_line.call(details_pairs(percent: percent)) lines.join("\n") end def model end private def percentage(num, total: count) total ||= count if num (num.to_f / total * 100).round(2) end end def build(requests) Hash.new(0).tap do |stats| stats[type] = count unless !requests || !requests.is_a?(Enumerable) || requests.empty? requests.each_with_index do |request| add_core_stats(stats, request || {}) add_account_stats(stats, request || {}) add_details_stats(stats, request || {}) end end end end def attrs_to_stat(stats, hash, attrs) stats.tap do |st| attrs.each {|attr| st[attr] += 1 if hash.key?(attr)} end end def add_core_stats(stats, request) stats["core"] += 1 if (request.keys & core_attrs).length > 0 attrs_to_stat(stats, request, core_attrs) end def add_account_stats(stats, request) if request.key?("account") stats["account"] += 1 stats["account_remove"] += 1 if !request["account"] attrs_to_stat(stats, request["account"] || {}, account_attrs) end end def add_details_stats(stats, request) if request.key?("details") stats["details"] += 1 stats["details_remove"] += 1 if !request["details"] if fields = request.dig("details", "fields") stats["fields"] += fields.length end end end def pairs(attrs, percent: false, total: count) pairs = attrs.map do |a| (v = attr(a, percent: percent, total: count)) > 0 ? [a, v] : nil end.compact end def core_pairs(percent: false) [["core", core(percent: percent)]] + pairs(core_attrs, percent: percent, total: core) end def account_pairs(percent: false) aattrs = ["account_remove"] + account_attrs [["account", account(percent: percent)]] + pairs(aattrs, percent: percent, total: account) end def details_pairs(percent: false) details_pairs = [["details", details(percent: percent)]] details_pairs += [["fields", fields_average]] if attr("fields") && fields_average details_pairs += pairs(["details_remove"], percent: percent, total: details) end end end end end end