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.

returning all requested objects in a standard Wavefront::Response wrapper.

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

api_caller[R]
args[R]
conn[R]
initial_limit[R]
method[R]
page_size[R]

Public Class Methods

new(api_caller, conn, method, *args) click to toggle source

@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

finalize_response(resp) click to toggle source

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
limit_and_offset(args) click to toggle source

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
make_lazy_call() click to toggle source

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
make_recursive_call() click to toggle source

'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
set_limit_and_offset(arg, page_size, offset) click to toggle source
# 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
set_pagination(offset, page_size, args) click to toggle source

@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
setup_vars() click to toggle source
# 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
user_page_size(args) click to toggle source

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