Class: Wavefront::Paginator::Base

Inherits:
Object
  • Object
show all
Defined in:
lib/wavefront-sdk/paginator/base.rb

Overview

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. Setting the limit to :all iteratively calls the Wavefront API, returning all requested objects an a standard Wavefront::Response wrapper; setting limit to :lazy returns a lazy Enumerable. The number of objects fetched in each API call, whether 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.

Direct Known Subclasses

Delete, Get, Post, Put

Instance Attribute Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(api_caller, conn, method, *args) ⇒ Base

Returns a new instance of Base.

Parameters:

  • api_caller (Wavefront::ApiCaller)

    the class which creates an instance of this one. We need to access its #response method.

  • conn (Faraday::Connection)
  • method (Symbol)

    HTTP request method

  • *args

    arguments to pass to Faraday’s #get method



35
36
37
38
39
40
41
# File 'lib/wavefront-sdk/paginator/base.rb', line 35

def initialize(api_caller, conn, method, *args)
  @api_caller  = api_caller
  @conn        = conn
  @method      = method
  @args        = args
  setup_vars
end

Instance Attribute Details

#api_callerObject (readonly)

Returns the value of attribute api_caller.



25
26
27
# File 'lib/wavefront-sdk/paginator/base.rb', line 25

def api_caller
  @api_caller
end

#argsObject (readonly)

Returns the value of attribute args.



25
26
27
# File 'lib/wavefront-sdk/paginator/base.rb', line 25

def args
  @args
end

#connObject (readonly)

Returns the value of attribute conn.



25
26
27
# File 'lib/wavefront-sdk/paginator/base.rb', line 25

def conn
  @conn
end

#initial_limitObject (readonly)

Returns the value of attribute initial_limit.



25
26
27
# File 'lib/wavefront-sdk/paginator/base.rb', line 25

def initial_limit
  @initial_limit
end

#methodObject (readonly)

Returns the value of attribute method.



25
26
27
# File 'lib/wavefront-sdk/paginator/base.rb', line 25

def method
  @method
end

#page_sizeObject (readonly)

Returns the value of attribute page_size.



25
26
27
# File 'lib/wavefront-sdk/paginator/base.rb', line 25

def page_size
  @page_size
end

Instance Method Details

#limit_and_offset(args) ⇒ Hash

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.

Parameters:

  • args (Array)

    arguments to be passed to a Faraday connection object

Returns:

  • (Hash)

    with keys :offset and :limit. Either’s value can be nil



58
59
60
61
62
63
64
65
# File 'lib/wavefront-sdk/paginator/base.rb', line 58

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_callEnumerable

Return all objects using a lazy enumerator.

Returns:

  • (Enumerable)

    with each item being

Raises:

  • (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.



126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
# File 'lib/wavefront-sdk/paginator/base.rb', line 126

def make_lazy_call
  offset = 0
  p_args = set_pagination(offset, page_size, args)

  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_callWavefront::Response

‘get’ eagerly. Re-run the get operation, merging together returned items until we have them all. rubocop:disable Metrics/MethodLength rubocop:disable Metrics/AbcSize

Returns:



99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
# File 'lib/wavefront-sdk/paginator/base.rb', line 99

def make_recursive_call
  offset = 0
  p_args = set_pagination(offset, page_size, args)
  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
    raise StopIteration unless resp.more_items?
  end

  ret
end

#set_pagination(offset, page_size, args) ⇒ Object

Parameters:

  • offset (Integer)

    where to start fetching from

  • page_size (Integer)

    how many objects to fetch

  • args (Array)

    arguments to pass to Faraday.get



81
82
83
84
85
86
87
88
89
90
91
# File 'lib/wavefront-sdk/paginator/base.rb', line 81

def set_pagination(offset, page_size, args)
  args.map do |arg|
    if arg.is_a?(Hash)
      arg.tap do |a|
        a[:limit] = page_size if a.key?(:limit)
        a[:offset] = offset if a.key?(:offset)
      end
    end
    arg
  end
end

#setup_varsObject



43
44
45
46
# File 'lib/wavefront-sdk/paginator/base.rb', line 43

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) ⇒ Object

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



71
72
73
74
75
# File 'lib/wavefront-sdk/paginator/base.rb', line 71

def user_page_size(args)
  arg_val = limit_and_offset(args)[:offset].to_i
  return arg_val if arg_val && arg_val > 0
  PAGE_SIZE
end