# Use case to update a register # @note # - You can define methods `filters` and `search` to change the target entries of the register # - You need to define the `process_ooze` method # This case expects `options[:source][:register_id]` class Eco::API::UseCases::OozeSamples::RegisterUpdateCase < Eco::API::UseCases::OozeSamples::OozeBaseCase include Eco::API::UseCases::OozeSamples::Helpers::Creatable class << self # @return [Integer] the number of pages to be processed in each batch def batch_size(size = nil) @batch_size ||= 25 return @batch_size unless size @batch_size = size end end name "register-update-case" type :other attr_reader :retrieved_oozes, :non_retrieved_oozes attr_reader :total_search_oozes, :dupped_search_oozes attr_reader :ooze_result_ids attr_reader :updated_oozes, :failed_update_oozes, :attempted_ooze_updates attr_reader :created_oozes, :ooze_create_attempts def main(session, options, usecase, mode: :legacy, &block) init_kpis super(session, options, usecase) do if mode == :legacy with_each_entry do process_ooze(&block) end elsif mode == :delegate raise "You need to pass a block when running main in `:delegate` mode" unless block_given? yield end end log_kpis end def process_ooze(_ooze = target) raise "You need to define this method" end private def before_loading_new_target(ooze_id) return unless (pending = queue_shift(ooze_id)) update_ooze(pending).tap do |result| if result.is_a?(Ecoportal::API::Common::Response) if result.success? @updated_oozes += 1 else @failed_update_oozes +=1 end end end end def new_target(object, warn_pending_changes: false) enqueue(object) super(object, warn_pending_changes: warn_pending_changes) do |pending| #enqueue(pending) end end # Main looper (invoked from `main`) def with_each_entry batched_search_results do |page_results| page_results.each do |page_result| if ooze_result_ids[page_result.id] @dupped_search_oozes += 1 else ooze_result_ids[page_result.id] = true end if (pending = queue_shift(page_result.id)) && dirty?(pending) msg = "Inconsistent search results. " msg << "Launching update on '#{object_reference(pending)}' to be able to queue it back" log(:warn) { msg } update_ooze(pending) end if (ooz = ooze(page_result.id)) @retrieved_oozes += 1 yield(ooz) else @non_retrieved_oozes += 1 log(:warn) { "Could not get page #{page_result.id}" } end end update_oozes end end def enqueue(object) return unless object.respond_to?(:id) unless object.is_a?(Ecoportal::API::V2::Page) or object.is_a?(Ecoportal::API::V2::Pages::PageStage) raise "Queuing is just for entries. Expecting Page or PageStage. Given: #{object.class}" end if (elem = queue_get(object.id)) msg = "Something is wrong. Native case 'RegisterUpdateCase' is " if (elem != object) && dirty?(elem) msg << "trying to queue different objects with same page id:\n" msg << " • already queued (changes will go): #{object_reference(elem)}\n" msg << " • tried to queue (lost changes): #{object_reference(object)}" log(:warn) { msg } end else batch_queue << object unless batch_queue.include?(object) end end def queue_shift(id = nil) if id batch_queue.delete(queue_get(id)) else batch_queue.shift end end def queue_get(id) batch_queue.find {|e| e.id == id} end def batch_queue @batch_queue ||= [] end def batched_search_results raise "Missing block. It yields in slices of #{self.class.batch_size} results" unless block_given? results_preview results = [] apiv2.registers.search(register_id, search_options) do |page_result| results << page_result if results.length >= self.class.batch_size yield(results) results = [] end end yield(results) unless results.empty? end # Launches the actual request to create the entry def create_ooze(draft, template_id:) @ooze_create_attempts += 1 if dry_run? dry_run_feedback(draft) false else apiv2.pages.create(draft, from: template_id).tap do @created_oozes += 1 end end end # Capture the attempts count def update_ooze(*args, **kargs, &block) @attempted_ooze_updates += 1 if dirty?(ooze) super end def update_oozes(batched_oozes = batch_queue) batched_oozes.each do |ooze| update_ooze(ooze).tap do |result| if result.is_a?(Ecoportal::API::Common::Response) if result.success? @updated_oozes += 1 else @failed_update_oozes +=1 end end end end batched_oozes.clear end def backup_patch!(ooze = target) return if (patch_doc(ooze) || {})["page"] log(:info) { "No changes to update for #{object_reference(ooze)}." } end def results_preview apiv2.registers.search(register_id, search_options.merge(only_first: true)).tap do |search_results| @total_search_oozes = search_results.total str_results = "Total target entries: #{search_results.total} (out of #{search_results.total_before_filtering})" default_answer = session.config.run_mode_remote?? "Y" : "N" session.prompt_user( "Do you want to proceed (y/N):", explanation: str_results, default: default_answer, timeout: 10 ) do |res| next if res.upcase.start_with?("Y") puts "..." log(:info) { "Aborting script..." } exit(0) end end end def init_kpis @total_search_oozes = 0 @retrieved_oozes = 0 @non_retrieved_oozes = 0 @dupped_search_oozes = 0 @ooze_result_ids = {} @updated_oozes = 0 @failed_update_oozes = 0 @attempted_ooze_updates = 0 @created_oozes = 0 @ooze_create_attempts = 0 end def log_kpis log(:info) { kpis_message } end def kpis_message msg = [] msg << "Run end:" msg << " • Search results: #{total_search_oozes}" msg << " • Duplicated search results #{dupped_search_oozes}" msg << " • Retrieved a total of #{retrieved_oozes}" msg << " • Could not get #{non_retrieved_oozes} oozes." msg << " • Updated #{updated_oozes} oozes (attempted: #{attempted_ooze_updates})." msg << " - Failed update on #{failed_update_oozes} oozes." msg << " • Created #{created_oozes} oozes (out of: #{ooze_create_attempts})." msg.join("\n") end def search_options @search_options ||= {}.tap do |opts| opts.merge!(sort: 'created_at') opts.merge!(dir: 'asc') opts.merge!(query: conf_search) if conf_search opts.merge!(filters: conf_filters) end end def conf_filters return filters if respond_to?(:filters) [] end def conf_search search if respond_to?(:search) end def register_id options.dig(:source, :register_id) end end