require 'base64' module Ecoportal module API class V2 # @attr_reader client [Ecoportal::API::Common::Client] a `Ecoportal::API::Common::Client` object that # holds the configuration of the api connection. class Registers extend Ecoportal::API::Common::BaseClass include Ecoportal::API::Common::Content::DocHelpers include Enumerable class_resolver :register_class, "Ecoportal::API::V2::Registers::Register" class_resolver :register_search_result_class, "Ecoportal::API::V2::Registers::PageResult" class_resolver :register_search_results, "Ecoportal::API::V2::Registers::SearchResults" attr_reader :client # @param client [Ecoportal::API::Common::Client] a `Ecoportal::API::Common::Client` object that # holds the configuration of the api connection. # @return [Registers] an instance object ready to make registers api requests. def initialize(client) @client = client end def each(params: {}, &block) return to_enum(:each, params: params) unless block get.each(&block) end # Gets all the registers via api request. # @return [Enumerable] an `Enumerable` with all schemas already wrapped as `Register` objects. def get response = client.get("/templates") Ecoportal::API::Common::Content::WrappedResponse.new( response, register_class, key: "registers" ) end # Gets all the oozes/pages of `register_id` matching the `options` # @param register_id [String] the `id` of the target register to search on. # @param options [Hash] the search options # @option options [Hash] :query plain search (like the search box in register). # @option options [Hash>] :filters the set of filters. # @option options [Boolean] if `true`, it only performs the first search and results `Ecoportal::API::V2::Registers::SearchResults`. # @yield [result] something to do with search page-result. # @yieldparam result [Ecoportal::V2::Registers::PageResult] a page result. # @return [Ecoportal::API::V2::Registers, Ecoportal::API::V2::Registers::SearchResults] def search(register_id, options = {}) # rubocop:disable Metrics/AbcSize only_first = options.delete(:only_first) options = build_options(options) if only_first response = client.get("/registers/#{register_id}/search", params: options) raise "Request failed - Status #{response.status}: #{response.body}" unless response.success? return register_search_results.new(response.body["data"]) end cursor_id = nil results = 0 total = nil loop do options.update(cursor_id: cursor_id) if cursor_id response = client.get("/registers/#{register_id}/search", params: options) raise "Request failed - Status #{response.status}: #{response.body}" unless response.success? data = response.body["data"] total ||= data["total"] if total != data["total"] msg = "Change of total in search results. " msg << "Probably due to changes that affect the filter" msg << "(register: #{register_id}):" print_search_status(msg, total, results, cursor_id, data, options) #total = data["total"] end unless total&.zero? results += data["results"].length print_progress(results, total) end data["results"].each do |result| object = register_search_result_class.new(result) yield object end break if total <= results unless data["cursor_id"] msg = "Possible error... finishing search for lack of cursor_id in response:" print_search_status(msg, total, results, cursor_id, data, options) end break unless (cursor_id = data["cursor_id"]) end self end private def build_options(options) # supply a query string # or a filter array (copy/paste from dev tools in the browser) options = {query: nil, filters: []}.update(options) {}.tap do |ret| options.each do |key, value| if key == :filters && value.any? ret[key] = {filters: value}.to_json elsif key ret[key] = value end end end end def print_search_status(msg, total, results, cursor_id, data, options) # rubocop:disable Metrics/ParameterLists msg += "\n" msg += " • Original total: #{total}\n" msg += " • Current total: #{data&.dig("total")}\n" msg += " • Total results retrieved: #{results}\n" msg += " • Cursor id: #{cursor_id} (#{Base64.decode64(cursor_id)})\n" msg += " • Current cursor results: #{data["results"]&.length}\n" msg += " • Next id: #{data["cursor_id"]} (#{Base64.decode64(data["cursor_id"])})\n" if data["cursor_id"] msg += " • Options:" puts msg pp options end def print_progress(results, total) percent = results * 100 / total msg = "Registers SEARCH" print "#{msg}: #{percent.round}% (of #{total})\r" $stdout.flush end end end end end require 'ecoportal/api/v2/registers/template' require 'ecoportal/api/v2/registers/register' require 'ecoportal/api/v2/registers/stage_result' require 'ecoportal/api/v2/registers/stages_result' require 'ecoportal/api/v2/registers/page_result' require 'ecoportal/api/v2/registers/search_results'