# rubocop:disable Naming/MethodParameterName module Eco module API class Session class Batch # The `Batch::Status` class aims to offer support to keep memory on: # 1. what has happened during the execution of a `Session::Batch` (i.e. errors) # 2. be able to build a summary of what happened # 3. gather the people that was returned as a result of the `batch` (for `get` batch type) # @attr_reader source_queue [Array, Array, # Array] # The queue as it was originally made (it could contain duplicates) # @attr_reader queue [Array, Array, Array] # `source_queue` with no repeated elements (**note**: observe that the elimination of duplicates could fail) # @attr_reader mode [Symbol] the `mode` that the `batch` was run with # @attr_reader root [Eco::API::Session::Job] the `job` that launched the `batch` class Status < Eco::API::Common::Session::BaseSession @modes = %i[exact search] class << self attr_reader :modes def valid_mode?(value) modes.include?(value) end end attr_reader :source_queue attr_reader :queue, :method, :mode # Nativelly to this gem, a batch against the server is lauched by an Eco::API::Session::Job. # When the batch returns the `BatchStatus`, the `Job` assigns itself as `root` of it. # @param object [Eco::API::Session::Job] attr_accessor :root # @param e [Eco::API::Common::Session::Environment] requires a session environment, # as any child of `Eco::API::Common::Session::BaseSession` # @param queue [Array, Array, Array] # the `source_queue` # @param method [Symbol] the type of `batch operation` # @param mode [Symbol] the mode of `batch operation`. It can be `:search` or `:exact` def initialize(ev, queue:, method:, mode: :exact) super(ev) msg = "In batch operations you must batch an Enumerable. Received: #{queue.class}" fatal(msg) unless queue.is_a?(Enumerable) self.mode = mode @method = method @source_queue = queue que = queue.to_a que = queue if queue.respond_to?(:uniq) if que.length != que.uniq.length log(:warn) { "Please, review your entries-to-query builder, you have repeated entries" } queue = que.uniq end @queue = queue @hash = @queue.each_with_index.map do |entry, i| [entry, i] end.to_h @responses = [] @person_match = [] @people_match = Array.new(@queue.length, []) end def mode=(value) msg = "Invalid :mode '#{value}'. You must specify mode: as one of #{self.class.modes} " fatal(msg) unless self.class.valid_mode?(value) @mode = value end # @return [Eco::API::Session::Batch::Errors] errors object helper def errors @errors ||= Eco::API::Session::Batch::Errors.new(status: self) end # @see Eco::API::Session::Batch::Errors#any? # @return [Boolean] `true` if there were Server errors, `false` otherwise def errors? errors.any? end # Get the assciated `reponse` of an input entry object `key` # @param key [Integer, Hash, Ecoportal::API::V1::Person, Ecoportal::API::Internal::Person] # these are the **index options**: # 1. `Integer`: index/position of the entry in the final `queue` # 2. `Hash`: entry queries can be raw `Hash` objects # 3. `Person` object: the most common case is to use the person # wrapper classes of the `Ecoportal::API` namespace. # @return [Ecoportal::API::Common::BatchResponse] def [](key) @responses[to_index(key)] end # Associates an input entry object `key` to its `response` # @param key [Integer, Hash, Ecoportal::API::V1::Person, Ecoportal::API::Internal::Person] # @see Eco::API::Session::Batch::Status#[] for `key` options # @param response key [Ecoportal::API::Common::BatchResponse] def []=(key, response) @responses[to_index(key)] = response end # Has the _entry_ `key` been queried to the server? # @param key [Integer, Hash, Ecoportal::API::V1::Person, Ecoportal::API::Internal::Person] # @return [Boolean] `true` if input entry `key` has an associated `Ecoportal::API::Common::BatchResponse` def received?(key) !!self[key] end # Has the _entry_ `key` 's query to the server been successful # @param key [Integer, Hash, Ecoportal::API::V1::Person, Ecoportal::API::Internal::Person] # @return [Boolean] `true` if input entry `key` has not had a server Error during the query def success?(key) self[key]&.success? end # Helper to transform any `key` to an `Integer` index # @param key [Integer, Hash, Ecoportal::API::V1::Person, Ecoportal::API::Internal::Person] # @return [Integer] the index that `key` has in the final `queue` def to_index(key) key.is_a?(Integer) ? valid_index(index: key) : valid_index(entry: key) end # _Index_ validator to make this object reliable # @return [Integer] the actual `index` def valid_index(index: nil, entry: nil) index ||= @hash[entry] return index if index && index < @queue.length msg = "You must provide either the index on the final 'queue' " msg << "or the original entry object of the batch. " msg << "Given, index=#{index.class}, entry:#{entry.class}" fatal msg end # @!group Get-specific helpers # The _person_ we got from the Server wrapped to the `Person` object for the input entry object `key` # @note it only makes sense when the used batch method was `get` # @param key [Integer, Hash, Ecoportal::API::V1::Person, Ecoportal::API::Internal::Person] # @see Eco::API::Session::Batch::Status#[] for `key` options # @return [Ecoportal::API::V1::Person, Ecoportal::API::Internal::Person] def person(key) self[key].result if success?(key) end # The _person_ we got from the Server wrapped to the `Person` object for the input entry object `key` # @note # - it only makes sense when the _batch method_ used was `get` with `q` # - **found using a search criteria** (`mode` == `:search`), as opposite # to find the person directly by `external_id` # @param key [Integer, Hash, Ecoportal::API::V1::Person, Ecoportal::API::Internal::Person] # @see Eco::API::Session::Batch::Status#[] for `key` options # @return [Ecoportal::API::V1::Person, Ecoportal::API::Internal::Person] def person_match(key) @person_match[to_index(key)] end def set_person_match(key, person) @person_match[to_index(key)] = person end def people_match(key) @people_match[to_index(key)] end def set_people_match(key, people) @people_match[to_index(key)] = people end # When the batch _method_ has been `get`, it gathers into an `Array` the people found. # @note here is where the used `mode` gets relevance: # - while `:exact` mode will keep the order of found people as per order of final `queue` # - `:search` mode will just gather the results (order won't match) # @raise [Exception] when the `method` of the batch operation was other than `get` # @return [Array, Array] # all the people that has been found. def people msg = "This batch wasn't a 'get'. Can't obtain people without 'get' method" fatal msg unless method == :get if mode == :exact out = Array(queue.length) @responses.each_with_index do |response, i| out[i] = response.result if response.success? end elsif mode == :search out = [] queue.each_with_index.map do |entry, _i| pers = person(entry) pers ||= person_match(entry) ppl = pers ? [pers] : people_match(entry) out += ppl end end out end # @!endgroup end end end end end # rubocop:enable Naming/MethodParameterName