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 ErrorCache = Struct.new(:type, :err, :entry, :response) # @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 # @return [Integer] the number of `entries` that got error. def count entries.length end # 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 # Groups `entries` with error `type` # @return [Hash] where each `key` is a `type` **error** and each value is an `Array` of: # 1. `entries` that got that error, if `only_entries` is `true` # 2. `ErrorCache` objects, if `only_entries` is `false` def by_type(only_entries: true) errors.group_by do |e| e.type end.transform_values do |arr| if only_entries arr.map {|e| e.entry} else arr end end end # @!endgroup # For all the `entries` with errors generates an `Array` of `ErrorCache` objects # @return [Array] where each `object` has # 1. `type` -> the error type `Class` # 2. `err` -> an instance object of that error `class` type # 3. `entry` -> the entry that generated the error # 4. `response` -> the original response from the server that carries the error def errors entries.each_with_object([]) do |entry, arr| response = status[entry] if body = response.body errs = [] if errs = body["errors"] || body["error"] errs = [errs].flatten(1).compact end if errs.empty? && !response.success? errs = [body["response"]].flatten(1).compact end errs.each do |msg| arr.push(ErrorCache.new( klass = Eco::API::Error.get_type(msg), klass.new(err_msg: msg, entry: entry, session: session), entry, response )) end end end end # @!group Messaging methods 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 def person_ref(entry) Eco::API::Session::Batch::Feedback.person_ref(entry) end private # 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.select.with_index 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? end end def get_attr(entry, attr) Eco::API::Session::Batch::Feedback.get_attr(entry, attr) end def get_row(value) Eco::API::Session::Batch::Feedback.get_row(value) 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 # 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}. Person: #{person_ref(entry)}" end msg end def print_one(key) unless status.success?(key) logger.error(str(key)) end end end end end end end