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.

  • 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 }

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



43
44
45
46
47
48
49
# 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

Instance Attribute Details

#api_callerObject (readonly)

Returns the value of attribute api_caller.



33
34
35
# File 'lib/wavefront-sdk/paginator/base.rb', line 33

def api_caller
  @api_caller
end

#argsObject (readonly)

Returns the value of attribute args.



33
34
35
# File 'lib/wavefront-sdk/paginator/base.rb', line 33

def args
  @args
end

#connObject (readonly)

Returns the value of attribute conn.



33
34
35
# File 'lib/wavefront-sdk/paginator/base.rb', line 33

def conn
  @conn
end

#initial_limitObject (readonly)

Returns the value of attribute initial_limit.



33
34
35
# File 'lib/wavefront-sdk/paginator/base.rb', line 33

def initial_limit
  @initial_limit
end

#methodObject (readonly)

Returns the value of attribute method.



33
34
35
# File 'lib/wavefront-sdk/paginator/base.rb', line 33

def method
  @method
end

#page_sizeObject (readonly)

Returns the value of attribute page_size.



33
34
35
# File 'lib/wavefront-sdk/paginator/base.rb', line 33

def page_size
  @page_size
end

Instance Method Details

#finalize_response(resp) ⇒ Object

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.)



137
138
139
140
141
142
# 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) ⇒ 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



66
67
68
69
70
71
72
73
# 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_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.



151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
# 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_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:



109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
# 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) ⇒ Object



96
97
98
99
100
101
# 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) ⇒ 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



90
91
92
93
94
# 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_varsObject



51
52
53
54
# 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) ⇒ 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



79
80
81
82
83
84
# 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