module Eco module API class Session class Batch # Helper object linked to a `Batch::Status`. Its aim is to manage the errors of the batch status. class Errors # @attr_reader status [Eco::API::Session::Batch::Status] `batch status` this `Errors` object is associated to. attr_reader :status # @param status [Eco::API::Session::Batch::Status] `batch status` this `Errors` object is associated to. def initialize(status:) "Expected Batch::Status as root. Given: #{status.class}" unless status.is_a?(Eco::API::Session::Batch::Status) @status = status end # @!group Status object shortcuts # @see [Eco::API::Session::Batch::Status#queue] def queue status.queue end # @see [Eco::API::Session::Batch::Status#method] def method status.method end # @param (see Eco::API::Session::Batch::Status#to_index) # @see [Eco::API::Session::Batch::Status#to_index] def to_index(*args) status.to_index(*args) end # @return [Eco::API::Session] currently active `session` def session status.session end def logger status.logger end # @!endgroup # @!group Pure errors helper methods # Was there any _Sever_ (reply) **error** as a result of this batch? # @return [Boolean] `true` if any of the queried _entries_ got an unsuccessful `Ecoportal::API::Common::BatchResponse` def any? queue.any? {|query| !status[query].success?} end # @return [Integer] the number of `entries` that got error. def count entries.length end # Input entries that got **error** response from the _Server_. # @raise [Exception] if there are elements of the final `queue` that did not get response # @note discards those that did not get _response_ from the Server (so those that were not queried) # - please, observe that this can only happen if there were repeated entries in the `source_queue` # @return [Array, Array, Array] def entries queue.each_with_index.map do |query, i| unless response = status[i] msg = "Error: query with no response. You might have duplicated entries in your queue.\n" msg += "Queue length: #{queue.length}; Queue elements class: #{queue.first.class}\n" msg += "Query with no response. Person: #{person_ref(query)}\n" queue.map do |entry| if [:id, :external_id, :email].any? {|attr| (v = get_attr(entry, attr)) && v == get_attr(query, attr)} msg += "It could be this peson entry (idx: #{to_index(entry)}): #{person_ref(entry)}\n" end end raise msg end response.success?? nil : query end.compact end # For all the `entries` with errors generates a `Hash` object # @return [Array] where each `Hash` has # 1. `:type` -> the error type # 2. `:err` -> the error `class` of that `:type` # 3. `:entry` -> the entry that generated the error def errors entries.each_with_object([]) do |entry, arr| if body = status[entry].body if errs = body["errors"] errs.each do |msg| arr.push({ type: klass = Eco::API::Error.get_type(msg), err: klass.new(err_msg: msg, entry: entry, session: session), entry: entry }) end end end end end # Groups `entries` with error `type` # @return [Hash] where each `key` is a `type` **error** and each value is # an `Array` of `entries` that got that error def by_type errors.group_by do |h| h[:type] end.transform_values do |arr| arr.map {|h| h[:entry]} end end # @!endgroup # @!group Messaging methods # Generates a `String` specifying the error for the entry `key`. # @param key [Integer, Ecoportal::API::V1::Person] # @return [String] the error description. def str(key) msg = "" unless status.success?(key) i = to_index(key) entry = queue.to_a[i] response = status[i] msg = "Error #{response.status}: #{response.body}\n" msg += "-- Failed to batch #{method} (entry #{i+1}). Person: #{person_ref(entry)}" end msg end # Sorts the entries that got server error by error `type` and generates the error messages. # @return [Array] the errors messages. def strs by_type.values.flatten(1).each_with_object([]) do |query, msgs| msgs.push(str(query)) end end def print_one(key) unless status.success?(key) logger.error(str(key)) end end def message msgs = strs if msgs.length > 0 "There were #{msgs.length} errors:\n" + msgs.join("\n") else "There were no errors for the current batch '#{method}'!! ;)" end end def print msgs = strs if msgs.length > 0 logger.error("There were #{msgs.length} errors:\n" + msgs.join("\n")) else logger.info("There were no errors for the current batch '#{method}'!! ;)") end end # @!endgroup private def person_ref(entry) "(id: '#{get_attr(entry, :id)}') '#{get_attr(entry, :name)}' ('#{get_attr(entry, :external_id)}': '#{get_attr(entry, :email)}')" end def get_attr(entry, attr) if entry.respond_to?(attr.to_sym) entry.public_send(attr.to_sym) elsif entry.is_a?(Hash) entry["#{attr}"] end end end end end end end