class Wavefront::Paginator::Base
Automatically handle pagination. This is an abstract class made concrete by an extension for each HTTP request type.
This class and its children do slightly unpleasant things with the HTTP request passed to us by the user, extracting and changing values in the URI, query string, or POST/PUT body. The POST class is particularly onerous.
Automatic pagination works by letting the user override the limit and offset values in API calls.
-
Calling with limit = :all iteratively calls the
Wavefront
API,
returning all requested objects in a standard Wavefront::Response
wrapper.
-
Calling with limit = :lazy returns a lazy Enumerable.
The number of objects fetched in each API call, eager or lazy, defaults to PAGE_SIZE, but the user can override that value by using the offset argument in conjunction with limit = :lazy | :all.
So, for example, to fetch all objects in blocks of ten (which could require a lot of API calls) you would use { limit: :all, offset: 10 }
Attributes
Public Class Methods
@param api_caller
[Wavefront::ApiCaller] the class which
creates an instance of this one. We need to access its #response method.
@param conn [Faraday::Connection] @param method [Symbol] HTTP request method @param *args arguments to pass to Faraday's get method
# File lib/wavefront-sdk/paginator/base.rb, line 43 def initialize(api_caller, conn, method, *args) @api_caller = api_caller @conn = conn @method = method @args = args setup_vars end
Public Instance Methods
In make_recursive_call
we've built up a composite response object. This method corrects a couple of things in that object which are misleading. (Because they're left over from the original call.)
# File lib/wavefront-sdk/paginator/base.rb, line 137 def finalize_response(resp) resp.tap do |r| r.response[:limit] = r.response.items.size - 1 r.response[:moreItems] = false end end
An API call may or may not have a limit and/or offset value. They could (I think) be anywhere. Safely find and return them. If multiple elements of @args have :limit or :offset keys, the last value wins.
@param args [Array] arguments to be passed to a Faraday
connection object
@return [Hash] with keys :offset and :limit. Either's value
can be nil
# File lib/wavefront-sdk/paginator/base.rb, line 66 def limit_and_offset(args) ret = { offset: nil, limit: nil } args.select { |a| a.is_a?(Hash) }.each_with_object(ret) do |arg, a| a[:limit] = arg[:limit] if arg.key?(:limit) a[:offset] = arg[:offset] if arg.key?(:offset) end end
Return all objects using a lazy enumerator. @return [Enumerable] with each item being @raise [Wavefront::Exception::EnumerableError] if an API error
is encountered at any point. The exception message is a Wavefront::Type::Status object, which will include the HTTP status code and any error string passed back by the API.
# File lib/wavefront-sdk/paginator/base.rb, line 151 def make_lazy_call offset = 0 p_args = set_pagination(offset, page_size, args) api_caller.verbosity(conn, method, *p_args) return if api_caller.opts[:noop] Enumerator.new do |y| loop do offset += page_size api_caller.verbosity(conn, method, *p_args) resp = api_caller.respond(conn.public_send(method, *p_args)) unless resp.ok? raise(Wavefront::Exception::EnumerableError, resp.status) end p_args = set_pagination(offset, page_size, p_args) resp.response.items.map { |i| y.<< i } raise StopIteration unless resp.more_items? end end.lazy end
'get' eagerly. Re-run the get operation, merging together returned items until we have them all. @return [Wavefront::Response]
rubocop:disable Metrics/MethodLength rubocop:disable Metrics/AbcSize
# File lib/wavefront-sdk/paginator/base.rb, line 109 def make_recursive_call offset = 0 p_args = set_pagination(offset, page_size, args) api_caller.verbosity(conn, method, *p_args) return if api_caller.opts[:noop] ret = api_caller.respond(conn.public_send(method, *p_args)) return ret unless ret.more_items? loop do offset += page_size p_args = set_pagination(offset, page_size, p_args) api_caller.verbosity(conn, method, *p_args) resp = api_caller.respond(conn.public_send(method, *p_args)) raise StopIteration unless resp.ok? ret.response.items += resp.response.items return finalize_response(ret) unless resp.more_items? end end
# File lib/wavefront-sdk/paginator/base.rb, line 96 def set_limit_and_offset(arg, page_size, offset) arg.tap do |a| a[:limit] = page_size if a.key?(:limit) a[:offset] = offset if a.key?(:offset) end end
@param offset [Integer] where to start fetching from @param page_size
[Integer] how many objects to fetch @param args [Array] arguments to pass to Faraday.get
# File lib/wavefront-sdk/paginator/base.rb, line 90 def set_pagination(offset, page_size, args) args.map do |arg| arg.is_a?(Hash) ? set_limit_and_offset(arg, page_size, offset) : arg end end
# File lib/wavefront-sdk/paginator/base.rb, line 51 def setup_vars @initial_limit = limit_and_offset(args)[:limit] @page_size = user_page_size(args) unless initial_limit.is_a?(Integer) end
How many objects to get on each iteration? The user can pass it in as an alternative to the offset argument, If it's not a positive integer, default to 999
# File lib/wavefront-sdk/paginator/base.rb, line 79 def user_page_size(args) arg_val = limit_and_offset(args)[:offset].to_i return arg_val if arg_val&.positive? PAGE_SIZE end